{"record":{"id":"9a28a0d5f7870f84","repo":"remotion-dev/remotion","slug":"expected-status-code-200-or-404-for-file-got-fi","errorCode":null,"errorMessage":"Expected status code 200 or 404 for file, got ${file.status}","messagePattern":"Expected status code 200 or 404 for file, got (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/studio/src/helpers/get-asset-metadata.ts","lineNumber":133,"sourceCode":"\t\tconst listedStaticFile =\n\t\t\tcanvasContent.type === 'asset'\n\t\t\t\t? window.remotion_staticFiles.find(\n\t\t\t\t\t\t(file) => file.name === canvasContent.asset && file.src === src,\n\t\t\t\t\t)\n\t\t\t\t: null;\n\t\tlet size = listedStaticFile?.sizeInBytes ?? null;\n\n\t\tif (size === null) {\n\t\t\tconst file = await fetch(src, {\n\t\t\t\tmethod: 'HEAD',\n\t\t\t});\n\n\t\t\tif (file.status === 404) {\n\t\t\t\treturn {type: 'not-found'};\n\t\t\t}\n\n\t\t\tif (file.status !== 200) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Expected status code 200 or 404 for file, got ${file.status}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst contentLength = file.headers.get('content-length');\n\n\t\t\tif (!contentLength) {\n\t\t\t\tthrow new Error('Unexpected error: content-length is null');\n\t\t\t}\n\n\t\t\tsize = Number(contentLength);\n\t\t}\n\n\t\tconst fetchedAt = Date.now();\n\t\tconst srcWithTime = addTime ? addAssetCacheBust({fetchedAt, src}) : src;\n\n\t\tconst fileType = getPreviewFileType(\n\t\t\tcanvasContent.type === 'asset' ? canvasContent.asset : src,","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/remotion-dev/remotion/blob/b2f4e34732f3c6c222ea029413e22dc402218cd7/packages/studio/src/helpers/get-asset-metadata.ts#L115-L151","documentation":"To show an asset's size in the Studio Timeline/asset views, `getAssetMetadata()` issues `fetch(src, {method: 'HEAD'})` when the static-file listing has no `sizeInBytes` (always true for output files, packages/studio/src/helpers/get-asset-metadata.ts:66). It tolerates exactly 200 and 404; any other status (403, 401, 405, 500, ...) throws this error, which is caught and surfaced as a `metadata-error` result. It means the HTTP server behind the asset URL rejected the HEAD request.","triggerScenarios":"A timeline asset (static file via `staticFile()` or a rendered output under `remotion_outputsBase`) whose URL returns a non-200/404 status to a HEAD request: expired or permission-denied signed URLs (403), auth-protected routes (401), servers/proxies that disallow HEAD (405), or backend errors (500/502).","commonSituations":"Assets on object storage (S3/R2) with expired signatures or missing HEAD permissions; CDN/auth proxies in front of the Studio that strip or block HEAD; broken output-serving routes in the dev server; assets added by path that no longer exist behind a redirecting proxy.","solutions":["Open the asset URL directly in a browser/curl and reproduce the status (`curl -I <src>`), then fix the server-side cause: refresh the signed URL, grant HEAD/read permission, or fix the failing route.","Ensure the serving layer allows HEAD and returns 200 with the same behavior as GET.","Prefer serving assets from the project `public/` folder so Studio's `remotion_staticFiles` listing already carries `sizeInBytes` and the HEAD request is skipped entirely.","If it is an output file, verify the outputs route of the Studio server is healthy and the file finished writing."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const verifyAssetHead = async (src: string): Promise<void> => {\n  const res = await fetch(src, {method: 'HEAD'});\n  if (res.status !== 200 && res.status !== 404) {\n    throw new Error(`Asset server returned ${res.status} for HEAD ${src}`);\n  }\n};\n\n// run before relying on Studio to display the asset's metadata","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Serve timeline assets from the project `public/` folder so Studio reads `sizeInBytes` from the static-file listing and never issues a HEAD request.","Ensure any asset host (S3/R2, CDN, auth proxy) permits HEAD and returns 200 for existing objects.","Prefer unexpired plain URLs over short-lived signed URLs for assets you inspect in the Timeline.","When an asset shows a metadata error in Studio, reproduce with `curl -I <src>` and fix the reported status on the server."],"tags":["http","head-request","asset-metadata","studio","network"],"backgroundTag":"unexpected-http-status-code","analyzedSha":"b2f4e34732f3c6c222ea029413e22dc402218cd7","analyzedAt":"2026-08-22T21:45:17.748Z","contentChangedAt":"2026-08-22T21:45:17.748Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}