API Troubleshooting Interview: Slow APIs and Unexpected Errors
How to answer two common SDE interview questions: diagnose and speed up a slow API (indexing, N+1, caching, payload size, async), and debug unexpected error…
Troubleshooting APIs: common questions
If an API response is slow, what steps would you take?
Measure first: find the slow endpoint and its p95, then open a trace to see where the time goes. Fix the biggest part first: add a missing index or batch N+1 queries, cache data that rarely changes, shrink the payload with fields, paging and compression, and move slow work like PDFs and emails to a queue and return 202.
How do you debug unexpected API error responses?
Check status codes to split client errors (4xx) from server errors (5xx) and see when they began and which version or region they come from. Inspect one failing call for its request ID, search aggregated logs for that ID, follow the distributed trace to the failing service, and check recent deploys. Roll back first, then fix the root cause.
Related chapters
- Start here in System Design
- How a system design interview is graded
- The delivery framework: five phases and a clock
- Numbers to know: what one machine can really do
- System Design Concepts: CAP, SQL vs NoSQL, Message Queues
- SQL vs NoSQL: How to Choose a Database (System Design)
- Traffic Jumps 10×: What Breaks First? (System Design)
- Proxy vs Load Balancer vs API Gateway (System Design)
- CAP Theorem Explained Simply, with Examples
- Why Use a Message Queue? System Design Explained
- Message Queue vs Pub/Sub vs Kafka: Differences
- Polling vs Long Polling vs SSE vs Webhooks (System Design)
- API design in System Design
- REST vs GraphQL vs gRPC: Choosing an API (System Design)
- API Goals Canvas: Design APIs from the Consumer
- REST API Design: Resources, Methods, Status Codes
- HTTP Semantics, Richardson Maturity Model and HATEOAS
- GraphQL Explained: Over-fetching, Schema, N+1 Problem
- RPC and gRPC Explained: Protobuf, HTTP/2, When to Use
- API Design Best Practices: 9 Principles with Examples
- API Payload Design: Names, Types, Links and Errors
- Mapping Database Tables to API Resources, Step by Step
- API Design for Complex Schemas: Trees, Polymorphism, Bookings
- API Pagination, Idempotency Keys, Errors and Versioning
- Network-Efficient APIs: HTTP Caching, ETags, Field Selection
- Async APIs: 202 Accepted, Webhooks and Bulk Operations
- API Versioning and Evolution Without Breaking Clients
- API Contracts: OpenAPI, Contract Testing and Docs
- API Security: Authentication, Authorization, Rate Limiting
- OAuth 2, OpenID Connect and Scopes for APIs
- OWASP API Top 10 Explained: BOLA, SSRF and More
- Running APIs: Gateways, Mesh, Rate Limits, Canaries
- API Design Review: A Staff-Level Capstone
- Spotify Web API: Resources, IDs, Payloads and Paging
- Spotify Web API: OAuth PKCE, Scopes, Quotas, Rate Limits
- Spotify Web API Changes: Real API Evolution Lessons
- Database-heavy designs in System Design
- Design a Distributed Key-Value Store (System Design Interview)
- Design a Hotel Reservation System (System Design Interview)
- Design a Digital Wallet (System Design Interview)
- Design S3-like Object Storage (System Design Interview)
- Games in System Design
- Shard City: Learn Database Sharding by Playing a Game
- System Design Case Studies: Flash Sale, Chat, ChatGPT
- Flash Sale System Design: Who Gets the Last Item
- Food Delivery App System Design: Which Database?
- Cache Stampede: Why the Database Fell Over and the Fix
- Live Streaming System Design: Scaling for a Final
- ChatGPT System Design: Streaming LLM Responses
- RAG System Design: Product Q&A on Sale Day
- IRCTC Tatkal System Design: Booking Under Extreme Load
- Group Chat System Design: WebSockets and Fan-Out
- Authentication in System Design: Sessions, JWT, OAuth
- Authentication Methods Compared: Sessions, JWT, OAuth
- JWT in System Design: Sessions, Revocation, Refresh Tokens
- JWT Interview Questions and Answers
- Life of a session, step by step
- JWT Structure Explained: Header, Payload, Signature
- Forge lab: why verification must be strict
- JWT vs Session Authentication: Which to Use
- The validation pipeline: where a bad request dies
- How to Revoke a JWT: Blocklists and Short Expiry
- Refresh Tokens and Rotation Explained
- Logout in depth: one device, all devices, SSO
- JWT Security Best Practices
- OAuth 2.0 and OpenID Connect Explained
- Where to Store JWT: localStorage vs HttpOnly Cookie
- JWT in Microservices: API Gateway vs Service Validation
- Microservices, keys, and trust boundaries
- Sender-constrained tokens: making a stolen token useless
- Authentication vs Authorization Middleware
- Failure explorer: what breaks when X fails
- Capacity planner: sessions vs JWT vs hybrid
- Edge cases catalog
- Test it, measure it, migrate to it
- Anti-patterns to reject in a design review
- Design checklist and cheat sheet
Keep learning
Overview
gateway + auth load envelope (full table scan) load 5 recipients, one query each (N+1) fetch template from template service render the PDF send 5 emails, one after another send 3 MB response (document as base64) Add an index on envelopes(public_id) Database indexing EXPLAIN showed a sequential scan over 4 million rows. With an index the lookup reads a few pages: 700 ms → 12 ms. Load recipients in one query Database (N+1) Cache templates in Redis (5 min) Caching layers Templates change rarely and are read on every send. A cache hit costs about 4 ms instead of a 300 ms service call. Invalidate on template edit. Asynchronous processing Return a summary + link, gzip it Payload size The response carried the whole document as base64. Return the envelope summary with a link to download the document, and compress: 3 MB → 4 KB. Add more servers This one request is slow even when the servers are idle. More servers help when requests queue for CPU, not when each request does slow work. p95 does not move. Raise the client timeout to 10 s Hiding the symptom Lab: POST /envelopes/env_7Hq/send takes 3.4 s at p95. The budget is 300 ms. p95 of this endpoint within budget against 300 ms The trace splits one slow request into its parts. Try fixes: each one only helps its own bar, so always start with the biggest. Status codes and error-rate dashboard HTTP status code checks Inspect one failing call (DevTools / curl) Network inspection The response is a Problem Details body with request_id req_9F2a and header x-served-by: send-v42-7c9. Sending the same request again usually succeeds: it lands on an old pod. Search the logs for req_9F2a Log aggregation One line, from send-service v42: “TimeoutError: template-service did not answer within 3000 ms”, mapped to 500 by a catch-all error handler. Open the distributed trace Distributed tracing send-service → template-service span: 3,000 ms, then cancelled. Inside template-service, a new query “templates by account and locale” takes 2.9 s: a full table scan. Only v42 calls this new endpoint. Check recent deploys and flags Change history 14:03: send-service v42 started a canary at 8% of traffic. It calls a new template endpoint added the same morning. The main database is down Then every version would fail, and much more than 8%. Clients send bad data Bad input gives 4xx, and the 4xx rate did not change. These are 500s. The v42 canary calls a new, unindexed template query that times out All clues agree: only v42 (8% canary), timeout to template-service, a 2.9 s full table scan in the trace. A network outage between regions A network problem would not pick only one version, and retries on old pods succeed. Lab: since 14:05, some users get “500 Internal Server Error” when they send a document for signing Pick tools in any order. Each one reveals a clue. No clues yet. (gather at least two strong clues first) Not this one. Fix now: roll the canary back to 0% (errors stop within a minute). Then: add the missing index in template-service, map the timeout to a 503/504 instead of a generic 500, and add an alert on error rate by version, so the canary stops itself next time.
Troubleshooting APIs: slow responses and unexpected errors
Two questions that interviewers love because they show how you work, not what you memorised: “your API is slow, what do you do?” and “your API returns errors nobody expected, how do you find out why?”. Candidates report both from SDE interviews, including at DocuSign. This chapter answers each with a method, a hands-on lab on an e-signature “send envelope” endpoint, and an answer you can say out loud.
One method for both questions
Scope it which endpoint, which users, since when, how bad percentiles and error rates, not one try trace and logs point at one layer Fix the biggest cause one change at a time Verify and guard compare numbers, add an alert or test Everyone, one customer, one region, one app version? One endpoint or all? Reads or writes? Big accounts only? Since when? Line it up with deploys, config changes, traffic peaks and dependency incidents. How bad? p50 vs p95 vs p99, error rate, how many users. That sets the urgency.
Scenario 1: the API response is slow
Step 2, fix the biggest bar first. In the lab, the PDF render and the full table scan are worth far more than any micro-optimisation. Each fix belongs to one of four families: Caching layers Payload size Return only needed fields, page lists, link big blobs instead of inlining them, compress with gzip or Brotli. Mobile users feel every megabyte. Async processing Work the caller need not wait for (PDFs, emails, webhooks) goes to a queue: 202 Accepted with a status link, workers in the background. If the trace shows… Look at Typical fix A query taking hundreds of ms EXPLAIN plan, rows scanned Index, rewrite the query, page Many small queries in a row Query count per request Batch with JOIN or IN (…), DataLoader Waiting before the query even starts Connection-pool wait time Pool size, slow transactions holding connections A slow call to another service That service’s own trace Cache it, call in parallel, set timeouts CPU-heavy work in the request Profiler, flame graph Move to a queue (async), or precompute Big response, slow on mobile only Response size, compression Fewer fields, paging, links, gzip Slow only after deploys or idle periods Cold starts, empty caches Warm-up, keep minimum instances Slow only at peak traffic CPU, queue length, saturation Scale out, rate limit, shed load Step 3, verify and guard. Compare p95 before and after on real traffic, not just in a test. Then add a latency budget alert for the endpoint, and a check in CI or load tests so the missing index cannot come back. Network-efficient APIs Long jobs and events go deeper on caching and 202 jobs.
Scenario 2, part 1: read the status code first
What it usually means First thing to check The request is wrong: missing field, bad format, failed validation Not authenticated: no token, expired or invalid token Token expiry, clock skew, the Authorization header actually sent Authenticated but not allowed Roles, scopes, ownership of the resource Wrong ID or route, deleted, or hidden on purpose Conflict with the current state Concurrent edits, duplicate create, wrong state transition Rate limited Retry-After header, the client’s request rate, retry loops A bug or unhandled error on the server Logs by request ID, recent deploys The gateway got a bad answer from upstream No capacity or not ready Health checks, overload, maintenance, circuit breakers The gateway gave up waiting for upstream “200 OK” with an error inside If the API hides failures in a 200 body, dashboards and retries are blind. The payload chapter’s rule: real status codes, one error shape. Status 0 / “network error” in the browser Often CORS, DNS, TLS or a blocked request: the request never got an HTTP answer the page may read. Check the network tab and the preflight. 4xx spike after a release A client and server disagree on the contract. Diff the API spec (the contracts chapter) and check old app versions.
Scenario 2, part 2: isolate the failing piece
Log aggregation what happened All services ship structured logs (JSON with request_id, user, version) to one place: ELK, Datadog, CloudWatch. Search one request ID across everything. Status code checks which side Error rate by status code, endpoint, version, region and customer. Splitting the graph is how you find “only v42” or “only one region”. Network inspection the raw exchange DevTools, curl -v, or a proxy: the exact request, headers, body, timing and response. Reproduce outside the app to rule the client in or out. Distributed tracing where in the chain One trace ID follows the request through every service (traceparent header, OpenTelemetry). The failing or slow span names the culprit. the payload chapter Running APIs set up. Without them, debugging a microservice error is guesswork across ten log files.
Make the next incident shorter
Alerts on symptoms Error rate and p95 per endpoint against an SLO, so you hear about it before customers do. Safe releases Canary and automatic rollback when the new version’s error rate rises. The lab’s incident would have stopped itself. Timeouts and clear errors Dashboards by dimension Split by version, region, endpoint and customer: most causes appear as “only X”. For each alert: what it means, the first three checks, how to roll back. Blameless post-mortems Write down cause, detection time and fix, and add the test or alert that would have caught it.
In the interview
“Slow API: first I scope and measure: which endpoint, p50 vs p95, since when, any deploy. Then I take a trace of a slow request and fix the biggest segment first. Usually that is the database: I run EXPLAIN, add the missing index and remove N+1 queries. Hot, rarely changing reads get a cache layer with clear invalidation. I cut the payload with field selection, paging and compression. And anything the user need not wait for, like PDF generation or emails, moves to a queue with a 202 and a status link. Finally I verify p95 on real traffic and add a latency alert.” “Unexpected errors: the status code tells me which side. 4xx means the request or auth, 5xx means the server or a dependency, 502/504 point at an upstream. I split the error rate by endpoint, version and region to find the ‘only X’. I inspect one failing call to get its request ID, search the aggregated logs for it, and open the distributed trace to find the failing span. I check recent deploys, roll back if a change caused it, then fix the root cause and add an alert so it is caught earlier next time.”
More courses
- Jobs, linked to lessons — Browse jobs where every requirement links to the chapter that teaches it. See how ready you are, how long the gap takes to close, and which listings look stale.
- Match a job post to courses — Paste a job post. Each skill is matched to a track here and put in learning order, foundations first.
- React from open source with patterns — Patterns extracted from Material UI, Radix, React Aria, React Hook Form, Redux Toolkit, TanStack, and Next.js — not slides about hooks.
- Database in depth — How a query becomes work. Indexes, isolation, locks, and the plans that explain why a page is slow — not an ORM tour.
- Build a real API with NestJS — One ticket-booking API, built in order: a plain Node server first, then NestJS modules, validation, a real database, and the features real clients lean on.
- Microservices — Microservice patterns one diagram at a time: how to split a monolith, how services talk, and how data stays consistent without distributed transactions.
- Kafka — A beginner-to-senior path through event logs, reliable delivery, production operations, and disaster recovery.
- AI engineering for software engineers — Eight free reads, in order, for software engineers moving into AI: when to build an agent, how to build one, how to test it, and how the model works underneath.
- Frontend system design — How a UI is sliced when it is a product, not a page: ownership of state, cache, routes, and what happens when the network lies.
- TypeScript in depth — The type system as a design tool. Inference, narrowing, generics, and the errors that mean the model is wrong — not a catalog of utility types.
- CSS in depth — See the box, then the page. Visual chapters from the box model through Flexbox surprises, Grid, selectors, and units, then backgrounds, shapes, and visual effects, each with a playground.
- Accessibility — Foundations first (WCAG in plain words, semantic HTML, lists, alt text), then hands-on HTML labs, a full pass of WAI-ARIA 1.3, and a final fix-the-page challenge.
- Docker — What an image is, why layers cache, and how containers find each other on a network.
- Redis — Fifteen Redis patterns, one picture each: cache, session, lock, counter, rate limiter, queue, and when Redis is the wrong tool.
- Kubernetes — Kubernetes from zero to operators: why it exists, Pods, Deployments and Services, then configuration, networking, storage, scheduling, scaling and security.