{"record":{"id":"a77fd7f2ce27e867","repo":"actualbudget/actual","slug":"invalid-config-file-key-key-must-be-a-non-ne","errorCode":null,"errorMessage":"Invalid config file: key \"${key}\" must be a non-negative integer","messagePattern":"Invalid config file: key \"(.+?)\" must be a non-negative integer","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/config.ts","lineNumber":94,"sourceCode":"  for (const key of Object.keys(value)) {\n    if (!configFileKeys.includes(key)) {\n      throw new Error(`Invalid config file: unknown key \"${key}\"`);\n    }\n    const v = value[key];\n    if (v === undefined) continue;\n    if (\n      (stringKeys as readonly string[]).includes(key) &&\n      typeof v !== 'string'\n    ) {\n      throw new Error(\n        `Invalid config file: key \"${key}\" must be a string, got ${typeof v}`,\n      );\n    }\n    if (\n      (numberKeys as readonly string[]).includes(key) &&\n      (typeof v !== 'number' || !Number.isInteger(v) || v < 0)\n    ) {\n      throw new Error(\n        `Invalid config file: key \"${key}\" must be a non-negative integer`,\n      );\n    }\n    if (\n      (booleanKeys as readonly string[]).includes(key) &&\n      typeof v !== 'boolean'\n    ) {\n      throw new Error(\n        `Invalid config file: key \"${key}\" must be a boolean, got ${typeof v}`,\n      );\n    }\n  }\n  return value as ConfigFileContent;\n}\n\nasync function loadConfigFile(): Promise<ConfigFileContent> {\n  const explorer = cosmiconfig('actual', {\n    searchStrategy: 'global',","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/cli/src/config.ts#L76-L112","documentation":"validateConfigFileContent type-checks every key in the parsed config file against known key schemas. For keys listed in numberKeys (numeric settings), the value must be a number that is an integer and >= 0. This error means a config file key that expects a non-negative integer was given a non-number, a float, or a negative value.","triggerScenarios":"A config file (loaded by loadConfigFile) contains a key in numberKeys whose value is a string (e.g. \"cacheTtl\": \"60\"), a negative number, or a non-integer float like 1.5.","commonSituations":"Hand-editing the config JSON and quoting numbers; setting a TTL/timeout to -1 intending 'unlimited'; pasting values from docs that use strings for durations.","solutions":["Open the config file and convert the offending key's value to a plain non-negative integer literal (remove quotes, no decimals, no negative sign).","If the key was meant to be disabled, remove the key entirely so the default is used instead.","Validate the JSON with a quick check: the value must satisfy Number.isInteger(v) && v >= 0."],"exampleFix":"// before (config.json)\n{ \"cacheTtl\": \"3600\" }\n// after\n{ \"cacheTtl\": 3600 }","handlingStrategy":"validation","validationCode":"function isValidConfigNumbers(cfg: Record<string, unknown>, numberKeys: readonly string[]): boolean {\n  return numberKeys.every(k => {\n    const v = cfg[k];\n    return v === undefined || (typeof v === 'number' && Number.isInteger(v) && v >= 0);\n  });\n}","typeGuard":"function isNonNegativeInt(v: unknown): v is number {\n  return typeof v === 'number' && Number.isInteger(v) && v >= 0;\n}","tryCatchPattern":"let fileConfig: ConfigFileContent;\ntry {\n  fileConfig = loadConfigFile(path);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Invalid config file')) {\n    console.error(`Config file ${path} has a bad value: ${err.message}`);\n    process.exit(1);\n  }\n  throw err;\n}","preventionTips":["Keep numeric config values as unquoted JSON numbers.","Never use -1 as a sentinel for 'unlimited' in config files.","Lint the config JSON with a schema validator (e.g. ajv) before loading.","After editing config by hand, re-run the command immediately to catch typos."],"tags":["config","validation","cli"],"backgroundTag":"schema-validation-failed","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}