{"record":{"id":"cc2c965b9b84ce69","repo":"angular/angular","slug":"value-not-a-number","errorCode":"VALUE_NOT_A_NUMBER","errorMessage":"${value} is not a number","messagePattern":"(.+?) is not a number","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"packages/common/src/pipes/number_pipe.ts","lineNumber":330,"sourceCode":"      throw invalidPipeArgumentError(CurrencyPipe, (error as Error).message);\n    }\n  }\n}\n\nfunction isValue(value: number | string | null | undefined): value is number | string {\n  return !(value == null || value === '' || value !== value);\n}\n\n/**\n * Transforms a string into a number (if needed).\n */\nfunction strToNumber(value: number | string): number {\n  // Convert strings to numbers\n  if (typeof value === 'string' && !isNaN(Number(value) - parseFloat(value))) {\n    return Number(value);\n  }\n  if (typeof value !== 'number') {\n    throw new RuntimeError(\n      RuntimeErrorCode.VALUE_NOT_A_NUMBER,\n      ngDevMode && `${value} is not a number`,\n    );\n  }\n  return value;\n}\n","sourceCodeStart":312,"sourceCodeEnd":337,"githubUrl":"https://github.com/angular/angular/blob/51cb07e98081ab7e4e84a9e0949266a8e19cca84/packages/common/src/pipes/number_pipe.ts#L312-L337","documentation":"The number pipes (DecimalPipe, PercentPipe, CurrencyPipe) accept number or numeric-string input. strToNumber() converts strings whose Number(v) and parseFloat(v) agree; anything that falls through — non-numeric strings like 'abc' or '1.2.3', objects, arrays, booleans — throws VALUE_NOT_A_NUMBER. Null, undefined, '' and NaN are filtered earlier and render as null.","triggerScenarios":"{{ price | number:'1.2-2' }} where price is 'N/A', '1.234,56' (decimal-comma string), an object, or a boolean; values arriving typed as any from a backend and bound straight into a number pipe.","commonSituations":"An API starts returning a sentinel string ('N/A', '-') or an object instead of a number; locale-formatted numeric strings (comma decimals) not normalized; optional fields typed number but actually something else.","solutions":["Validate and coerce at the data boundary: Number(v), check Number.isFinite, else map to null","Show a fallback in the template for non-numeric values instead of piping them","For decimal-comma strings, parse with a dedicated pipe before the number pipe"],"exampleFix":"// before\n{{ item.price | number:'1.2-2' }} <!-- '1.234,56' or 'N/A' throws -->\n\n// after\nexport function toNumber(v: unknown): number | null {\n  if (typeof v === 'number') return Number.isFinite(v) ? v : null;\n  if (typeof v === 'string') { const n = Number(v.replace(',', '.')); return Number.isFinite(n) ? n : null; }\n  return null;\n}\n{{ toNumber(item.price) | number:'1.2-2' }}","handlingStrategy":"type-guard","validationCode":"function isNumericInput(v: unknown): boolean {\n  if (v == null || v === '') return true;  // pipes render these as empty\n  if (typeof v === 'number') return true;\n  if (typeof v === 'string') {\n    const n = Number(v);\n    return Number.isFinite(n) && n === parseFloat(v);\n  }\n  return false;\n}","typeGuard":"function isParsableNumber(v: unknown): v is number | string {\n  if (typeof v === 'number') return true;\n  if (typeof v === 'string') { const n = Number(v); return Number.isFinite(n); }\n  return false;\n}","tryCatchPattern":"transform(value: unknown, digits?: string): string | null {\n  if (!isParsableNumber(value)) return null;\n  return this.decimal.transform(value as number, digits);\n}","preventionTips":["Coerce and validate numeric fields at the API boundary with Number() + Number.isFinite","Type models strictly (number or numeric string), never any","Render a dash/placeholder for sentinel values ('N/A') instead of piping them"],"tags":["number-pipe","pipes","type-validation","type-coercion"],"backgroundTag":"type-coercion-failed","analyzedSha":"51cb07e98081ab7e4e84a9e0949266a8e19cca84","analyzedAt":"2026-08-22T07:04:54.531Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}