{"record":{"id":"c8eaf09a8cf3c630","repo":"remotion-dev/remotion","slug":"failed-to-load-font-json-stringify-fonturl-response-status","errorCode":null,"errorMessage":"Failed to load font ${JSON.stringify(fontUrl)}: ${response.status} ${response.statusText}","messagePattern":"Failed to load font (.+?): (.+?) (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/font-face-registry.ts","lineNumber":30,"sourceCode":"\tweight: string | null;\n\tstretch: string | null;\n\tunicodeRange: string | null;\n\tvariant: string | null;\n};\n\nconst registeredFontFaces: RegisteredFontFace[] = [];\nconst fontDataByUrl = new Map<string, Promise<ArrayBuffer>>();\n\nexport const fetchFontData = (fontUrl: string): Promise<ArrayBuffer> => {\n\tconst cached = fontDataByUrl.get(fontUrl);\n\tif (cached) {\n\t\treturn cached;\n\t}\n\n\tconst promise = fetch(fontUrl)\n\t\t.then((response) => {\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to load font ${JSON.stringify(fontUrl)}: ${response.status} ${response.statusText}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn response.arrayBuffer();\n\t\t})\n\t\t.catch((error) => {\n\t\t\tfontDataByUrl.delete(fontUrl);\n\t\t\tthrow error;\n\t\t});\n\n\tfontDataByUrl.set(fontUrl, promise);\n\treturn promise;\n};\n\nexport const registerFontFace = (fontFace: RegisteredFontFace) => {\n\tif (\n\t\tregisteredFontFaces.some(","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/remotion-dev/remotion/blob/46a3a6bf13ca367376ff18bbb06dae2e87e0d068/packages/core/src/font-face-registry.ts#L12-L48","documentation":"Remotion fetches @font-face font files at composition time so they can be embedded during rendering. If the HTTP response for the font URL is not ok (e.g. 404, 403, 500), fetchFontData throws with the URL and status. Rendering fails fast rather than silently falling back to a missing font.","triggerScenarios":"Loading a font via loadFont/FontFace with a URL that returns a non-2xx status; expired signed URLs; CORS-proxied or blocked font hosts returning error pages.","commonSituations":"Typo'd font URL; font removed from CDN; S3/GCS presigned URL expired; local dev server not running when rendering; network restrictions in Lambda/CI.","solutions":["Verify the font URL returns 200 (curl -I the URL).","Fix or re-upload the font asset / regenerate presigned URLs.","Use a local font file path or hosted URL that is reachable from the render environment.","Check network/firewall and CORS settings in the rendering environment."],"exampleFix":"// before\nawait loadFont({family: 'X', url: 'https://cdn.example.com/old-font.woff2'})\n// after\nawait loadFont({family: 'X', url: 'https://cdn.example.com/font-v2.woff2'}) // verified 200","handlingStrategy":"retry","validationCode":"const res = await fetch(fontUrl, {method: 'HEAD'});\nif (!res.ok) throw new Error(`Font unavailable: ${res.status}`);","typeGuard":null,"tryCatchPattern":"try {\n  await loadFont({family, url: fontUrl});\n} catch (e) {\n  if (String(e).includes('Failed to load font')) {\n    await loadFont({family, url: fallbackFontUrl});\n  }\n}","preventionTips":["Pre-verify font URLs return 200 before rendering.","Avoid short-lived presigned URLs in render environments.","Self-host fonts next to the project or bundle them via staticFile().","Check network egress in Lambda/CI."],"tags":["network","http","font"],"backgroundTag":"http-error-response","analyzedSha":"46a3a6bf13ca367376ff18bbb06dae2e87e0d068","analyzedAt":"2026-09-18T00:12:20.256Z","contentChangedAt":"2026-09-18T00:12:20.256Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}