{"record":{"id":"4ce953eb3a137286","repo":"trpc/trpc","slug":"unsupported-media-type-4ce953","errorCode":"UNSUPPORTED_MEDIA_TYPE","errorMessage":"Unsupported content-type \"${req.headers.get('content-type')}","messagePattern":"Unsupported content-type \"(.+?)","errorType":"error_code","errorClass":"TRPCError","httpStatus":415,"severity":"error","filePath":"packages/server/src/unstable-core-do-not-import/http/contentType.ts","lineNumber":307,"sourceCode":"\nconst handlers = [\n  jsonContentTypeHandler,\n  formDataContentTypeHandler,\n  octetStreamContentTypeHandler,\n];\n\nfunction getContentTypeHandler(req: Request): ContentTypeHandler {\n  const handler = handlers.find((handler) => handler.isMatch(req));\n  if (handler) {\n    return handler;\n  }\n\n  if (!handler && req.method === 'GET') {\n    // fallback to JSON for get requests so GET-requests can be opened in browser easily\n    return jsonContentTypeHandler;\n  }\n\n  throw new TRPCError({\n    code: 'UNSUPPORTED_MEDIA_TYPE',\n    message: req.headers.has('content-type')\n      ? `Unsupported content-type \"${req.headers.get('content-type')}`\n      : 'Missing content-type header',\n  });\n}\n\nexport async function getRequestInfo(\n  opts: GetRequestInfoOptions,\n): Promise<TRPCRequestInfo> {\n  const handler = getContentTypeHandler(opts.req);\n  return await handler.parse(opts);\n}\n","sourceCodeStart":289,"sourceCodeEnd":321,"githubUrl":"https://github.com/trpc/trpc/blob/acff82332de8b4562d3e6975fa8d94ab1a6de5e0/packages/server/src/unstable-core-do-not-import/http/contentType.ts#L289-L321","documentation":"`getContentTypeHandler` matches the request against registered handlers (JSON, formData, octet-stream). If none match and the method is not GET (GET falls back to JSON so endpoints open in a browser), the request is rejected as UNSUPPORTED_MEDIA_TYPE, echoing the offending content-type.","triggerScenarios":"Sending an unsupported type such as `text/xml` or `application/x-www-form-urlencoded` with a non-GET method; a content-type with parameters that defeat the `startsWith` matcher.","commonSituations":"Wrong serializer on the client; a client defaulting to form-urlencoded; a version mismatch where a handler was removed or renamed.","solutions":["Send `application/json` (or one of the supported content-types) from the client.","Ensure client and server versions agree on the supported content-type set.","For raw uploads use `application/octet-stream` with POST; for form uploads use `multipart/form-data` with POST."],"exampleFix":"// before\nfetch('/api/trpc/user.get', {\n  method: 'POST',\n  headers: { 'content-type': 'application/x-www-form-urlencoded' },\n  body: 'id=1',\n})\n\n// after\nfetch('/api/trpc/user.get', {\n  method: 'POST',\n  headers: { 'content-type': 'application/json' },\n  body: JSON.stringify({ id: 1 }),\n})","handlingStrategy":"validation","validationCode":"// Validate content-type against the supported set\nconst SUPPORTED = ['application/json', 'multipart/form-data', 'application/octet-stream'];\nfunction assertSupportedContentType(ct: string | null): void {\n  if (!ct || !SUPPORTED.some((s) => ct.startsWith(s))) {\n    throw new Error(`Unsupported content-type: ${ct}`);\n  }\n}","typeGuard":"function isSupportedContentType(ct: string | null): boolean {\n  return !!ct && ['application/json', 'multipart/form-data', 'application/octet-stream']\n    .some((s) => ct.startsWith(s));\n}","tryCatchPattern":"try {\n  await trpc.proc.mutate(body);\n} catch (e) {\n  if (e instanceof TRPCError && e.code === 'UNSUPPORTED_MEDIA_TYPE') {\n    // Switch the request to application/json (or another supported type)\n  }\n  throw e;\n}","preventionTips":["Send one of the supported content-types from the client.","Keep client and server versions aligned so the supported set matches.","For raw uploads use octet-stream with POST; for form uploads use multipart/form-data with POST."],"tags":["http","content-type","method"],"backgroundTag":null,"analyzedSha":"acff82332de8b4562d3e6975fa8d94ab1a6de5e0","analyzedAt":"2026-08-12T22:04:41.179Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}