actualbudget/actual · error · Error
Invalid config file: key "${key}" must be a non-negative int
Error message
Invalid config file: key "${key}" must be a non-negative integer What it means
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.
Source
Thrown at packages/cli/src/config.ts:94
for (const key of Object.keys(value)) {
if (!configFileKeys.includes(key)) {
throw new Error(`Invalid config file: unknown key "${key}"`);
}
const v = value[key];
if (v === undefined) continue;
if (
(stringKeys as readonly string[]).includes(key) &&
typeof v !== 'string'
) {
throw new Error(
`Invalid config file: key "${key}" must be a string, got ${typeof v}`,
);
}
if (
(numberKeys as readonly string[]).includes(key) &&
(typeof v !== 'number' || !Number.isInteger(v) || v < 0)
) {
throw new Error(
`Invalid config file: key "${key}" must be a non-negative integer`,
);
}
if (
(booleanKeys as readonly string[]).includes(key) &&
typeof v !== 'boolean'
) {
throw new Error(
`Invalid config file: key "${key}" must be a boolean, got ${typeof v}`,
);
}
}
return value as ConfigFileContent;
}
async function loadConfigFile(): Promise<ConfigFileContent> {
const explorer = cosmiconfig('actual', {
searchStrategy: 'global',View on GitHub (pinned to d4334cb6e6)
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.
Example fix
// before (config.json)
{ "cacheTtl": "3600" }
// after
{ "cacheTtl": 3600 } Defensive patterns
Strategy: validation
Validate before calling
function isValidConfigNumbers(cfg: Record<string, unknown>, numberKeys: readonly string[]): boolean {
return numberKeys.every(k => {
const v = cfg[k];
return v === undefined || (typeof v === 'number' && Number.isInteger(v) && v >= 0);
});
} Type guard
function isNonNegativeInt(v: unknown): v is number {
return typeof v === 'number' && Number.isInteger(v) && v >= 0;
} Try / catch
let fileConfig: ConfigFileContent;
try {
fileConfig = loadConfigFile(path);
} catch (err) {
if (err instanceof Error && err.message.startsWith('Invalid config file')) {
console.error(`Config file ${path} has a bad value: ${err.message}`);
process.exit(1);
}
throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Invalid config file: expected an object with keys: ${configF
- Invalid config file: unknown key "${key}"
- Invalid config file: key "${key}" must be a string, got ${ty
- Invalid --name: must be a non-empty string.
- No update fields provided. Use --name or --offbudget.
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/a77fd7f2ce27e867.
Report an issue: GitHub.