← Amazon Interview Insights

Amazon·Research Engineer·Onsite - Coding / Algorithms·Staff

StaffPrefer not to say
Apr 2026

Summary

Amazon onsite coding round for a principal-level RE role, centered entirely on designing a recursive JSON schema validator from scratch. The class hierarchy mattered as much as whether the code ran, which I did not fully appreciate until I was already in the room.

Questions Asked (3)

Q1

Design and implement a recursive schema validator: given an arbitrary nested data structure and a schema definition, verify that the data conforms to expected types, required fields, and nested shapes. Return whether validation passes, and on failure, return the path where it broke.

System DesignAlgorithms & Data StructuresTechnical Trade-offs
Author's notes

I went straight to coding and regretted it.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements and defining the schema representation, then outline a recursive algorithm that traverses both schema and data in parallel, accumulating the path. Discuss trade-offs like recursion depth, error handling, and performance, and consider edge cases such as cyclic data or ambiguous schemas.

Pro tip: Emphasize that returning the exact failure path is crucial for debuggability, and mention that you'd design the validator to collect all errors (not just the first) for better developer experience, while still returning the first failure path if required.

1. Clarify requirements and schema definition

Ask about the schema format (e.g., JSON Schema-like), supported types, required fields, nested structures, and whether to return all errors or just the first. Define the data structures for schema and validation result.

2. Design recursive validation function

Outline a function that takes schema, data, and current path. It checks type, required fields, and recursively validates nested objects/arrays, building the path as it goes.

3. Handle edge cases and error reporting

Address missing fields, type mismatches, extra fields, arrays, null/undefined, and cyclic references. Decide on error format: return a boolean and path, or a list of errors.

4. Analyze complexity and trade-offs

Discuss time/space complexity (O(n) where n is number of nodes), recursion depth limits, iterative alternatives, and performance optimizations like early exit.

5. Test with examples and conclude

Walk through a sample nested data and schema, showing how the algorithm finds the failure path. Summarize key decisions and potential extensions.

Key Points to Mention

  • Schema representation: types, required fields, nested schemas, arrays, and optional fields.
  • Recursive traversal with path tracking (e.g., using dot notation or array indices).
  • Error handling: return first failure path or collect all errors; distinguish between missing vs. wrong type.
  • Edge cases: null/undefined, empty objects/arrays, extra fields, cyclic data, and deep nesting.
  • Complexity: O(n) time and space, recursion depth concerns, and iterative alternatives.
  • Trade-offs: strict vs. lenient validation, performance vs. detailed error reporting, and extensibility.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

How would you handle edge cases like missing required keys, extra unknown properties, type mismatches (including int vs float), null values in non-nullable fields, and mixed-type array items?

Algorithms & Data StructuresTechnical Trade-offs
Author's notes

Ran out of time before covering all of these, which I think is pretty common.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the context: is this for data validation, API input handling, or schema enforcement? Then propose a layered validation strategy that distinguishes between recoverable and fatal errors, with clear policies for each edge case. Emphasize trade-offs between strictness and flexibility, and how you'd log or surface issues for debugging.

Pro tip: At Amazon, always tie your approach to customer impact and operational excellence—e.g., how strict validation prevents downstream failures but might reject valid data, so you'd use configurable policies and metrics to monitor rejection rates.

1. Clarify requirements and context

Ask about the data source, schema definition, and whether validation should be strict or lenient. Determine if the system is batch or real-time, and what the consequences of accepting invalid data are.

2. Define a validation policy per edge case

For each edge case (missing keys, extra properties, type mismatches, nulls, mixed arrays), decide whether to reject, coerce, ignore, or log. For example, missing required keys might be fatal, while extra properties could be ignored with a warning.

3. Implement layered validation

Use a schema validation library (e.g., JSON Schema, Pydantic) for structural checks, then add custom logic for nuanced cases like int vs float coercion or mixed-type arrays. Ensure validation is centralized and reusable.

4. Handle errors gracefully and observably

Return clear error messages with paths to offending fields, log validation failures with context, and emit metrics to monitor frequency of each edge case. Consider dead-letter queues for unrecoverable data.

5. Discuss trade-offs and alternatives

Explain why you chose strict vs lenient handling, and how you'd balance data quality with system resilience. Mention potential performance impacts and how to mitigate them.

Key Points to Mention

  • Schema validation libraries (e.g., JSON Schema, Pydantic, Cerberus) and their pros/cons
  • Coercion rules: when to allow int-to-float conversion (e.g., 1 -> 1.0) and when to reject
  • Handling nulls in non-nullable fields: reject vs. substitute default vs. fail fast
  • Mixed-type arrays: enforce homogeneity, allow union types, or reject with clear error
  • Logging and monitoring: track validation failures to identify upstream issues
  • Trade-offs: strict validation ensures data integrity but may reduce flexibility; lenient validation improves usability but risks downstream errors

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

Follow-up: how would you extend this validator to support schema references (like $ref in JSON Schema), including handling circular references?

System DesignTechnical Trade-offs
Author's notes

Did not see this coming.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by outlining a two-phase approach: first, resolve all $ref pointers into a fully dereferenced schema graph, then validate against that graph. For circular references, use a visited set or memoization to avoid infinite loops, and consider lazy resolution or graph traversal with cycle detection. Emphasize trade-offs between eager vs. lazy resolution and how you'd handle errors like unresolved refs.

Pro tip: Mention that you'd treat the schema as a directed graph and use DFS with a visited set to detect cycles, and that you'd cache resolved schemas to avoid redundant work—this shows you think about performance and correctness.

1. Clarify requirements and scope

Ask whether $ref can be local (within the same document) or remote (external files/URLs), and whether circular references are allowed or should be flagged as errors. This sets the stage for design decisions.

2. Design a reference resolution strategy

Propose a resolver that builds a map of all $ref pointers to their targets, either by pre-processing the schema or resolving on-demand. Discuss using JSON Pointer (RFC 6901) for local refs and URI resolution for remote refs.

3. Handle circular references

Explain that you'd detect cycles during resolution using a visited set or by tracking the resolution stack. For validation, you can either break cycles by treating them as recursive schemas or use lazy evaluation to validate only when needed.

4. Integrate with the validator

Modify the validator to accept a resolved schema graph and traverse it, using memoization to avoid re-validating the same subschema. Ensure error messages point to the original $ref location for debuggability.

5. Discuss trade-offs and optimizations

Compare eager vs. lazy resolution: eager is simpler but may fail on circular refs; lazy is more complex but handles cycles gracefully. Mention caching resolved schemas and using iterative instead of recursive traversal to avoid stack overflows.

Key Points to Mention

  • JSON Pointer (RFC 6901) for local references and URI resolution for remote references
  • Cycle detection using DFS with a visited set or memoization
  • Eager vs. lazy resolution and their trade-offs
  • Caching resolved schemas to improve performance
  • Error handling for unresolved or invalid references
  • Recursive schema validation and avoiding infinite loops

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.