Skip to content
FiveCord Docs

Responses and limits

Almost every failed Media Proxy request answers with a short text/plain reason phrase and nothing else. The Media Proxy has no request-count rate limit, so every bound below is a resource bound.

An unsuccessful response body is an English reason phrase under the content type text/plain; charset=utf-8. The JSON HTTP API error response never appears here. HEAD returns the same status and headers with an empty body. The method rejection of a registered path2 and a locally unsatisfiable range have neither a body nor a Content-Type.

StatusBodyCondition
400Bad requestAn invalid storage key, dimension, format, or external path, an unparsable relay partNumber, a failed attachment or external transformation, or a relay upload body the endpoint failed to read from the client1
401UnauthorizedAn invalid signed external path signature, a missing, malformed, or expired relay capability, or a missing or invalid internal bearer token
403ForbiddenA relay capability presented for another bucket, key, method, uploadId, or partNumber, /_metrics requested from a non-loopback address, or a public read whose Origin the cross-origin read policy refuses
404Not foundA GET or HEAD of an unrouted path or of any read path on a relay endpoint, an object that does not exist, or a relay PUT outside upload and relay mode
404This content is no longer available.4An attachment read enforce refuses, or a missing attachment object under enforce
405Method not allowed2A method other than GET or HEAD on a read route or on an unrouted path
413Payload too largeA stored object, external body, upload body, or internal request body beyond its bound
500Transcode failedAn image asset transcode failed and the source is not directly displayable
500Internal server errorA relay spool write to the endpoint’s own disk failed
502Bad gatewayAn object store read or write failed, an external origin fetch failed, an external origin redirected in a loop or more than five times, or an external origin returned an unsuccessful status that the Media Proxy does not pass through, or an outbound socket deadline or a relay object storage write deadline expired
503Service unavailableThe upload relay spool budget is exhausted, an external buffer reservation or allocation failed, or an external origin answered /_metadata with 4293
504Gateway timeoutA transformation admission slot was unavailable or the transformation deadline expired

1 The relay also answers 400 when the client connection fails part way through the body

2 The registered paths, /_health, /_metrics, /_metadata, /_sniff, /_thumbnail, /_frames, and /v1/relay/{key}, answer an unaccepted method with an empty body, no Content-Type, and an Allow header. All seven are registered in every mode, so the method rejection is the same in every mode, even where the path itself answers 404

3 /_metadata is the only endpoint that remaps an origin 429. The signed external read route retains 429 as 429

4 Sent under the enforce signed attachment URL policy alone, where it also replaces Not found for an attachment object that does not exist. Under report every response is the one off returns, so a missing object keeps the Not found body there

When the Media Proxy passes an external origin status through to the client, the body is Upstream fetch failed on the signed external read route. On /_metadata, the body is the canonical reason phrase of that status. An object store error that maps to no case above uses the canonical reason phrase of its status.

Every error a route produces uses Cache-Control: no-store and the standard security headers. The exceptions have the security headers and set no cache policy, and Cache policies names them. No plain-text error has CORS headers unless it came from the upload relay, and no error has Retry-After or a request identifier. Under the enforce cross-origin read policy, every GET or HEAD error on a read path has Vary: Accept-Encoding, Origin. That includes the 403 for a refused Origin.

The set of reason phrases is open. A client MUST branch on the HTTP status and MUST NOT parse, compare, or pattern-match the body. A phrase can be reworded and a new condition can introduce one without a version change. A client MUST NOT expect a JSON body on a failure, and MUST NOT expect a failure to name the key, parameter, or field that caused it.

Every HEAD response has an empty body, so the Body column describes GET, PUT, and POST.

StatusBodyCondition
2001Media bytes, or an empty HEAD or relay PUT bodyA complete representation was served or a relay write succeeded
206Selected media bytes for GET and empty for HEADOne byte range is satisfiable
400Media error responseA path, query, target, transformation, or relay request is invalid
401Media error responseAn external path signature, a relay capability, or an internal token is invalid
403Media error responseThe cross-origin read policy denied the request, a relay capability does not match the request, or an external origin returned 403
404Media error responseThe route or object does not exist, a relay endpoint received a read, the relay is not served here, an attachment signature was refused, or an external origin returned 404
4052Media error responseThe route rejects the method, or an external origin returned 405
406, 408, 409, 410, 411, 412, 414, 415, 428, 4293Media error responseAn external origin returned that status
413Media error responseA source, external response, or upload exceeds its applicable bound
4164empty locally, otherwise Media error responseA local range is unsatisfiable, or an external origin returned 416
500Media error responseAn image asset transcode failed with no usable source, or a relay spool write failed
502Media error responseAn object store, external origin, or upload destination returned an unusable response
503Media error responseUpload spool capacity is exhausted, an external buffer reservation or allocation failed, or an external origin answered /_metadata with 4295
504Media error responseTransformation capacity was unavailable or a transformation deadline expired

1 The internal endpoints /_metadata, /_sniff, and /_frames answer 200 with JSON, /_health with plain text, and /_metrics with the Prometheus text exposition

2 A read route path, or any other path outside the registered paths, answers with the media error response. Each registered path answers with an empty body, no Content-Type, and an Allow header

3 These statuses occur only when an external origin returned that status and the Media Proxy passed it through

4 A locally unsatisfiable range answers with an empty body, Content-Range: bytes */{size}, and Accept-Ranges: bytes, and has no Content-Type and no cache policy

5 The remap produces a service unavailable response, which is indistinguishable from a budget exhaustion 503

An external origin status of 400, 401, 403, 404, 405, 406, 408, 409, 410, 411, 412, 413, 414, 415, 416, 428, or 429 reaches the client unchanged as an upstream fetch failure. The origin response body and headers are not forwarded. Any other unsuccessful origin status becomes 502.

The Media Proxy evaluates no conditional request header and never redirects a noncanonical target, so it returns no 304 and no 308.

Proxied or stored media is limited to 500 MiB, and exceeding that returns 413. The bound applies to a streamed object, a buffered object, an external response body, and any input selected for transformation. When a streamed external body passes the bound only after the response head is committed, the Media Proxy truncates it.

A decoded signed external target URL is limited to 8,192 bytes, and a longer URL returns 400. The route follows at most five redirects. A sixth redirect or a redirect loop returns 502. Every redirect target is subject to the same URL limit and the same public address check, which blocks non-public IP addresses and every port other than 80 and 443.

Decoded images are limited to 16,384 pixels on either edge and 268,435,456 pixels in total. Animated input is limited to 20,000 frames and 1,073,741,824 decoded pixels across all frames. No configuration changes these bounds. Transformations defines the resulting failure statuses.

The upload relay limits a body to the smaller of the authorised upload size and the endpoint body limit. That endpoint limit defaults to 500 MiB and can be configured from 1 byte through 5 GiB.

An internal /_metadata, /_sniff, /_thumbnail, or /_frames request body is limited to the base64 expansion of the 500 MiB media bound plus 1 MiB. All answer a larger body with 413.

A transformation returns 504 when capacity is unavailable or its deadline expires. Upload and external-media requests can return 503 when their capacity is exhausted.

DeadlineDefaultConfigurable range
Outbound socket connect and total timeout130,000 ms0 through 300,000 ms
Transformation15,000 ms1,000 through 120,000 ms
Upload relay object storage write2900,000 ms1,000 through 3,600,000 ms

1 One value sets both the connect timeout and the total request timeout, and it applies to external origin fetches, to object storage requests, and to the response body streamed back to the client

2 A relay write with a declared Content-Length extends this deadline by one second for every 16 KiB of declared length

The same socket timeout bounds every streamed response body. A streamed stored object and a streamed signed external response terminate when the gap between two body chunks exceeds that timeout. The whole transfer has a second deadline of that timeout plus one second for every 16 KiB of expected length, which is a floor of 16 KiB per second. A body that ends before, or runs past, the advertised Content-Length also terminates with an error.

An animated response can be shortened to meet its deadline or playback limit. See Transformation limits.

Every successful media representation uses Cache-Control: public, max-age=31536000 and CDN-Cache-Control: public, max-age=31536000. An audio or video representation appends no-transform to Cache-Control only. Signed external media uses the same policy as stored media.

No route sets immutable, Expires, ETag, or Last-Modified on a read response. A cache revalidates a representation by fetching it again.

One read selects a shorter policy. Under the report or enforce signed attachment URL policy, an attachment read whose signature is valid gets public, max-age= the seconds left on that signature in both headers, so no entry outlives the URL that made it. A data package URL never expires, so it gets the one-day ceiling instead. Every other read, and every attachment read under off, keeps the year.

A one-year max-age is only safe where a purge path reaches every cache that stores media. With no ETag and no Last-Modified there is nothing to revalidate against, so a deleted or replaced object is served until its entry is purged or drops out. A cache with no purge path must set a shorter lifetime of its own instead. Caching in front of FiveCord states how.

Every route-produced error response uses Cache-Control: no-store, and a successful /_metrics read uses it too. A 416 response, a successful upload relay response, and the empty-body method rejection of a registered path set no cache policy at all.

A complete media response has Accept-Ranges: bytes, the representation Content-Type, and an exact Content-Length1. Outside static mode that Content-Type is text/plain; charset=utf-8 when it names a JavaScript media type, and a 200 or 206 with no Content-Type gets the same value. Content detection defines both rules. A 206 also sets Content-Range to the selected interval over the complete size and Content-Length to the selected byte count. A 416 has Content-Range: bytes */{size} and Accept-Ranges: bytes with an empty body.

1 A streamed signed external response omits Content-Length when the origin declared none

HEAD applies the same range contract as GET and returns 206 or 416 with an empty body. A forwarded external range is answered with the origin Content-Range and Content-Length unchanged. Byte ranges defines which request ranges are recognised.