Backend interview: How would you design an HTTP 413 Content Too Large contract?
Prompt and scope
A video upload passes through a CDN, API gateway, application service, and object store, each with a different accepted size. Design the 413 Content Too Large response, limit discovery, resumable upload, Retry-After, error body, and monitoring.
This is a backend API reliability question. The number of layers and video size are assumptions, not frequency claims.
What the interviewer is testing
- Whether you separate permanent limits, temporary capacity, and body-validation failure.
- Whether you explain the relationship between 413 and Retry-After precisely.
- Whether you design resumability instead of retrying the full body.
- Whether you handle proxy limits, idempotency, and information leakage.
Clarifying questions to ask
- Which layer emitted 413, and are its scope and request ID preserved?
- Is the limit per request, tenant, object, time window, or remaining quota?
- Can the client use chunks, resume, and query an upload session?
- Is the limit fixed configuration or temporary capacity or quota?
- Can received bytes create billing, locks, or object metadata side effects?
A 30-second answer
“413 means the server refuses to process content that is too large. A fixed limit should not make the client wait; a temporary condition may include Retry-After. The edge should reject early with a stable code, request ID, and public constraint, while the application still validates actual bytes. Large files use an upload session, chunks, and an idempotent completion. After a disconnect, query state before resending; never resend confirmed chunks. I measure 413 by layer, tenant, and size.”
Step-by-step design
1. Define layered limits
Fixed maximums, tenant quotas, object policy, and runtime capacity need clear owners. An edge can reject from Content-Length, but the application must also check received bytes, decompressed size, and content policy. Include a request ID in the error; do not reveal internal nodes, disk capacity, or another tenant’s data.
2. Use Retry-After correctly
RFC 9110 allows a server to generate Retry-After when the 413 condition is temporary. The value can be an HTTP date or delay seconds. A fixed maximum needs a changed request or chunks, not waiting. Use the header for a known quota or maintenance recovery window, and have clients cap and validate the delay.
HTTP/1.1 413 Content Too Large
Retry-After: 120
Content-Type: application/problem+json
X-Request-Id: req-81a3. Make the error actionable
Return a stable code, scope, allowed upload mode, maximum chunk size, and an upload-session entry point. Never expose gateway implementation names, stack traces, or database errors. The client can compress, resize, chunk, or request quota based on the code instead of retrying the same body forever.
4. Provide resumable upload
Create an upload session first and return its ID, expiry, chunk-size range, and a query for completed chunks. Each chunk carries a digest and idempotency key; completion references only verified chunks. On 413, the client can reduce a new chunk or create a new session without retransmitting confirmed data.
5. Handle inconsistent layers
The gateway may return 413 before the application, while the application may reject after decompression, quota, or policy checks. A shared error model cannot assume every layer knows the final limit. Return current constraints at session creation, monitor 413 sources, and do not cache one layer’s temporary value as a permanent global limit.
6. Tie retries, billing, and metrics together
Classify 413 at the client: change the request for a fixed limit, follow Retry-After for a temporary limit, and query session state after a session failure. Use idempotency for completion so billing is not duplicated, and expire abandoned sessions. Track source layer, tenant, request size, uploaded bytes, Retry-After compliance, chunk retransmission, and final recovery to detect limit drift.
Model high-quality answer
“I first identify the emitting layer and limit type. A fixed maximum returns 413 with a public constraint or chunk entry point; only temporary quota or capacity returns Retry-After. Large files use sessions and chunks with digests and idempotency, and a disconnected client queries confirmed chunks. The edge rejects early, while the application checks actual and decompressed bytes. The error body exposes only a stable code, request ID, and next step. I measure source, size distribution, waiting compliance, duplicate completion, and recovery rate.”
Common mistakes
- Adding Retry-After to every 413 → fixed limits cause useless waits → use time only for temporary conditions.
- Hard-coding one client limit → layers drift → return session constraints and monitor the source.
- Resending the whole body → bandwidth and side effects multiply → use chunks, queries, and idempotent completion.
- Checking only Content-Length → decompressed or actual bytes can exceed limits → validate during and after ingestion.
- Exposing internal limits → topology and capacity leak → return a stable code and request ID.
Follow-up questions and responses
What should a client do when 413 has no Retry-After?
Do not guess a delay. Treat it as a fixed or unknown limit, use the error code and session state, and switch to a smaller request, chunks, or an explicit quota flow. Automate waiting only when the server gives a recovery time.
What if a chunk also exceeds one layer’s limit?
Return the currently allowed range at session creation and choose a chunk no larger than the smallest effective limit. If policy changes, preserve confirmed chunks and continue with new session parameters instead of resubmitting old chunks.
The gateway returned 413 but the application has no record. How do you debug it?
Compare request IDs, received bytes, and response source across edge, gateway, and application. If the application has no record, inspect gateway limits, routing, and body forwarding first; missing application logs do not prove an application rejection.