{"record":{"id":"8fd1374cafcb7787","repo":"expo/expo","slug":"declares-which-is-set-to-json-stringify-valu","errorCode":null,"errorMessage":"${declares}, which is set to ${JSON.stringify(value)} — not a finite number. An axis takes a number in the range the font declares, such as -10 for \"slnt\".","messagePattern":"(.+?), which is set to (.+?) — not a finite number\\. An axis takes a number in the range the font declares, such as -10 for \"slnt\"\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/expo-font/plugin/src/withFontsAndroid.ts","lineNumber":214,"sourceCode":"\n    if (!AXIS_TAG_PATTERN.test(tag)) {\n      throw new Error(\n        `${declares}, which holds characters no axis tag uses. A tag begins with a letter, then letters, digits, or the trailing spaces that pad a shorter tag. ${consequence}`\n      );\n    }\n\n    if (\n      registeredAxisTags.includes(lowercaseTag) &&\n      lowercaseTag !== tag &&\n      !isFoundryAxisTag(tag)\n    ) {\n      throw new Error(\n        `${declares}, which names no axis: tags are case sensitive. Write it as ${JSON.stringify(lowercaseTag)}. ${consequence}`\n      );\n    }\n\n    if (typeof value !== 'number' || !Number.isFinite(value)) {\n      throw new Error(\n        `${declares}, which is set to ${JSON.stringify(value)} — not a finite number. ` +\n          `An axis takes a number in the range the font declares, such as -10 for \"slnt\".`\n      );\n    }\n  }\n}\n\nexport function warnAboutUnknownAxisTags(fontsByFamily: GroupedFontObject) {\n  for (const { tag, value, declares } of collectDeclaredAxes(fontsByFamily)) {\n    if (value === undefined) {\n      continue;\n    }\n\n    const lowercaseTag = tag.toLowerCase();\n\n    // A font may declare `SLNT`, so this stays legal — but it is far more often `slnt` in the\n    // wrong case, and Android then applies nothing.\n    if (isFoundryAxisTag(tag) && registeredAxisTags.includes(lowercaseTag)) {","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/expo/expo/blob/da586c407bd53c4369a994e6ed5d6cf3340420f5/packages/expo-font/plugin/src/withFontsAndroid.ts#L196-L232","documentation":"Thrown by assertValidAxes (withFontsAndroid.ts:214) when the value assigned to an axis is not a finite number — i.e. typeof value !== 'number' || !Number.isFinite(value). Strings ('-10'), NaN, Infinity, or booleans are rejected; an axis takes a plain number in the range the font declares, such as -10 for 'slnt'. Note undefined values are skipped, so app.config.ts conditionals may legally produce undefined.","triggerScenarios":"Writing axes: { slnt: '-10' } (string from JSON), { wght: NaN }, { opsz: Infinity }, or parsing axis values from a remote config/env as strings in app.config.ts and passing them into the expo-font plugin config.","commonSituations":"Reading variation settings from a CMS or .env (always strings) without Number() conversion; JSON configs where numbers get quoted; computations producing NaN.","solutions":["Convert values to plain numbers: Number(value) or write literals unquoted","If the value comes from env/CMS, validate with Number.isFinite(Number(raw)) before passing to the plugin","Drop the axis entry (or set it to undefined in a conditional app.config.ts) instead of passing NaN/'-'"],"exampleFix":"// before (app.config.ts)\naxes: { slnt: process.env.SLANT, wght: Number(process.env.WEIGHT || 'NaN') }\n// after\naxes: {\n  slnt: process.env.SLANT != null ? Number(process.env.SLANT) : undefined,\n  wght: Number.isFinite(Number(process.env.WEIGHT)) ? Number(process.env.WEIGHT) : undefined,\n}","handlingStrategy":"validation","validationCode":"function assertFiniteAxisValues(axes: Record<string, unknown>) {\n  for (const [tag, value] of Object.entries(axes)) {\n    if (value === undefined) continue; // app.config.ts conditionals may write undefined\n    if (typeof value !== 'number' || !Number.isFinite(value)) {\n      throw new Error(`Axis ${tag} must be a finite number, got ${JSON.stringify(value)}`);\n    }\n  }\n}","typeGuard":"const isFiniteAxisValue = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v);","tryCatchPattern":null,"preventionTips":["Wrap env/CMS-sourced values in Number(...) and check Number.isFinite before building the font config","Quote-free JSON: make sure numbers in app.json are not written as strings"],"tags":["expo-font","android","config-plugin","variable-fonts","font-axes","type-mismatch"],"backgroundTag":"invalid-font-axes-config","analyzedSha":"da586c407bd53c4369a994e6ed5d6cf3340420f5","analyzedAt":"2026-08-23T00:40:06.936Z","contentChangedAt":"2026-08-23T00:40:06.936Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}