{"record":{"id":"ea417a2f926d1d81","repo":"calcom/cal.diy","slug":"unsupported-content-type-expected-contenttype","errorCode":null,"errorMessage":"Unsupported Content-Type. Expected ${contentType}","messagePattern":"Unsupported Content-Type\\. Expected (.+?)","errorType":"http","errorClass":"HttpError","httpStatus":415,"severity":"warning","filePath":"apps/web/app/api/parseRequestData.ts","lineNumber":50,"sourceCode":"  if (contentType.includes(\"application/json\")) {\n    try {\n      return await req.json();\n    } catch (e) {\n      log.error(`Invalid JSON: ${e} from path ${req.nextUrl}`);\n      throw new HttpError({ statusCode: 400, message: \"Bad Request (Invalid JSON)\" });\n    }\n  }\n\n  if (contentType.includes(\"application/x-www-form-urlencoded\")) {\n    return await parseUrlFormData(req);\n  }\n\n  if (contentType.includes(\"multipart/form-data\")) {\n    return await parseMultiFormData(req);\n  }\n\n  log.error(`Unsupported content type: ${contentType} from path ${req.nextUrl}`);\n  throw new HttpError({ statusCode: 415, message: `Unsupported Content-Type. Expected ${contentType}` });\n}\n","sourceCodeStart":32,"sourceCodeEnd":52,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/web/app/api/parseRequestData.ts#L32-L52","documentation":"Thrown by parseRequestData (HttpError, HTTP 415 Unsupported Media Type) when the request Content-Type is neither application/json, application/x-www-form-urlencoded, nor multipart/form-data. The message echoes the unsupported content-type so the caller knows what was received vs expected.","triggerScenarios":"POST/PUT with a Content-Type the dispatcher does not handle, e.g. text/plain, application/xml, an empty type, or a multipart type with an unexpected parameter.","commonSituations":"Client forgot to set Content-Type (defaults to text/plain in some fetch setups), sending XML/text to a JSON-only endpoint, custom content-type not yet supported, charset-only variations.","solutions":["Set Content-Type to one of: application/json, application/x-www-form-urlencoded, or multipart/form-data on the request.","Default the client to application/json for structured payloads.","If you genuinely need a new content-type, extend parseRequestData to handle it rather than relying on the fallback."],"exampleFix":"// before\nawait fetch('/api/x', { method: 'POST', body: 'hello' }); // Content-Type defaults to text/plain\n\n// after\nawait fetch('/api/x', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({ msg: 'hello' }),\n});","handlingStrategy":"validation","validationCode":"// Send a supported Content-Type\nconst SUPPORTED = ['application/json', 'application/x-www-form-urlencoded', 'multipart/form-data'];\nif (!SUPPORTED.some(t => contentType.startsWith(t))) {\n  throw new Error(`Unsupported Content-Type: ${contentType}`);\n}\nawait fetch('/api/x', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body });","typeGuard":"function isSupportedContentType(ct: string): boolean {\n  return ['application/json', 'application/x-www-form-urlencoded', 'multipart/form-data']\n    .some(t => ct.includes(t));\n}","tryCatchPattern":"try {\n  await parseRequestData(req);\n} catch (e) {\n  if (e instanceof HttpError && e.statusCode === 415) {\n    return Response.json({ error: e.message }, { status: 415 });\n  }\n  throw e;\n}","preventionTips":["Default clients to application/json for structured data.","Explicitly set Content-Type on every request rather than relying on defaults.","Extend parseRequestData if a new content-type must be supported."],"tags":["request-parsing","content-type","unsupported-media-type","validation"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}