{"record":{"id":"9ccb6aa0a9019ab0","repo":"remotion-dev/remotion","slug":"called-measuretext-with-fontfamily-json-str","errorCode":null,"errorMessage":"Called measureText() with \"fontFamily\": ${JSON.stringify(fontFamily)} but it looks like the font is not loaded at the time of calling.\nA measurement with the fallback font ${computedFallback} was taken and had the same dimensions, indicating that the browser used the fallback font.\nSee https://remotion.dev/docs/layout-utils/best-practices for best practices.","messagePattern":"Called measureText\\(\\) with \"fontFamily\": (.+?) but it looks like the font is not loaded at the time of calling\\.\nA measurement with the fallback font (.+?) was taken and had the same dimensions, indicating that the browser used the fallback font\\.\nSee https://remotion\\.dev/docs/layout-utils/best-practices for best practices\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/layout-utils/src/layouts/measure-text.ts","lineNumber":178,"sourceCode":"\n\t\tconst sameAsFallbackFont =\n\t\t\tboundingBox.height === boundingBoxOfFallbackFont.height &&\n\t\t\tboundingBox.width === boundingBoxOfFallbackFont.width;\n\n\t\t// Ensure there are at least 4 unique characters, with just a few, there is more likely to be a false positive\n\t\tif (\n\t\t\tsameAsFallbackFont &&\n\t\t\tcomputedFallback !== computedFontFamily &&\n\t\t\tnew Set(text).size > 4\n\t\t) {\n\t\t\tconst err = [\n\t\t\t\t`Called measureText() with \"fontFamily\": ${JSON.stringify(\n\t\t\t\t\tfontFamily,\n\t\t\t\t)} but it looks like the font is not loaded at the time of calling.`,\n\t\t\t\t`A measurement with the fallback font ${computedFallback} was taken and had the same dimensions, indicating that the browser used the fallback font.`,\n\t\t\t\t'See https://remotion.dev/docs/layout-utils/best-practices for best practices.',\n\t\t\t];\n\t\t\tthrow new Error(err.join('\\n'));\n\t\t}\n\t}\n\n\tconst result = {height: boundingBox.height, width: boundingBox.width};\n\twordCache.set(key, result);\n\treturn result;\n};\n","sourceCodeStart":160,"sourceCodeEnd":186,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/layout-utils/src/layouts/measure-text.ts#L160-L186","documentation":"When measureText() is called with validateFontIsLoaded: true, it measures the text twice (with the requested fontFamily and with no family / fallback). If both measurements match exactly, the requested font and the fallback differ in the computed style, and the text has at least 5 unique characters, the library concludes the requested font was never actually loaded and the browser silently substituted the fallback — a common cause of layout drift. It throws to force you to await font load.","triggerScenarios":"Calling measureText() with validateFontIsLoaded:true before @remotion/google-fonts / @remotion/fonts / a <Font> load has resolved; using a fontFamily name that does not match the loaded font's CSS family name; rendering on a frame where the font fetch is still in flight.","commonSituations":"Forgetting to delayRender until fonts load; referencing a font by file name instead of its CSS family name; mixing @remotion/google-fonts with a manual <link> that races; measureText being called synchronously during the first frame before the FontFace is ready.","solutions":["Load the font via @remotion/fonts (staticFile + <Font>) or @remotion/google-fonts and wait for its load promise before measuring.","Use delayRender/continueRender to gate the component until `document.fonts.ready` or the font's onLoad fires.","Verify the fontFamily string exactly matches the font's CSS family name (case- and space-sensitive).","If you must measure early, pass validateFontIsLoaded:false and accept fallback-tolerance."],"exampleFix":"// before\nconst dims = measureText({text: title, fontFamily: 'Inter', fontSize: 24, validateFontIsLoaded: true});\n// after\nconst handle = delayRender('load Inter');\nuseEffect(() => {\n  document.fonts.load('700 24px Inter').then(() => continueRender(handle));\n}, []);","handlingStrategy":"validation","validationCode":"const fontReady = await document.fonts.load(`${fontWeight ?? 400} ${fontSize}px ${fontFamily}`);\n// only measure after this resolves","typeGuard":"export const isFontLoaded = async (family: string): Promise<boolean> => {\n  try { await document.fonts.load(`16px \"${family}\"`); return true; }\n  catch { return false; }\n};","tryCatchPattern":"try {\n  const dims = measureText({text, fontFamily, fontSize, validateFontIsLoaded: true});\n} catch (e) {\n  if (/font is not loaded/i.test((e as Error).message)) {\n    await document.fonts.ready; // then retry\n  } else throw e;\n}","preventionTips":["Load fonts with @remotion/fonts or @remotion/google-fonts and await their load promise.","Gate the measuring component with delayRender until document.fonts.ready.","Use the exact CSS family name (case- and space-sensitive).","Avoid passing validateFontIsLoaded:true on the very first frame if fonts are still loading."],"tags":["typescript","layout-utils","fonts","validation","dom"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}