actualbudget/actual · error · Error
Invalid ${name}: expected a non-negative integer, got ${valu
Error message
Invalid ${name}: expected a non-negative integer, got ${value} What it means
validateNonNegativeInt is a final guard applied to resolved numeric options (cacheTtl, lockTimeout) after CLI/env/config merging. It throws when a value reached it that is not an integer or is negative. It backs the earlier parseNonNegativeIntFlag parsing so non-numeric option strings fail too.
Source
Thrown at packages/cli/src/config.ts:140
],
});
const result = await explorer.search();
if (result && !result.isEmpty) {
return validateConfigFileContent(result.config);
}
return {};
}
function parseNonNegativeIntEnv(
raw: string | undefined,
source: string,
): number | undefined {
return raw === undefined ? undefined : parseNonNegativeIntFlag(raw, source);
}
function validateNonNegativeInt(value: number, name: string): number {
if (!Number.isInteger(value) || value < 0) {
throw new Error(
`Invalid ${name}: expected a non-negative integer, got ${value}`,
);
}
return value;
}
export async function resolveConfig(
cliOpts: CliGlobalOpts,
): Promise<CliConfig> {
const fileConfig = await loadConfigFile();
const serverUrl =
cliOpts.serverUrl ??
process.env.ACTUAL_SERVER_URL ??
fileConfig.serverUrl ??
'';
const password =View on GitHub (pinned to d4334cb6e6)
Solutions
- Change the option value to a non-negative integer, e.g. --cache-ttl=300.
- Remove the flag/env/config entry to use the default value.
- If you need to disable caching, check the docs for the supported mechanism rather than using -1.
Example fix
// before $ actual-cli --cache-ttl=-1 // after $ actual-cli --cache-ttl=300
Defensive patterns
Strategy: validation
Validate before calling
const raw = process.env.ACTUAL_CACHE_TTL;
if (raw !== undefined && (!/^[0-9]+$/.test(raw) || parseInt(raw, 10) < 0)) {
throw new Error(`ACTUAL_CACHE_TTL must be a non-negative integer, got ${raw}`);
} Type guard
function isNonNegativeInt(v: unknown): v is number {
return typeof v === 'number' && Number.isInteger(v) && v >= 0;
} Try / catch
try {
await runCommand(argv);
} catch (err) {
if (err instanceof Error && err.message.startsWith('Invalid ')) {
console.error(`Bad numeric option: ${err.message}`);
process.exit(2);
}
throw err;
} Prevention
- Validate CLI/env numerics with a regex like ^[0-9]+$ before invoking.
- Avoid -1 sentinels; omit the option to use defaults.
- Document accepted ranges for cacheTtl/lockTimeout in your team's runbooks.
- Parse flags with a typed parser (e.g. commander/zod) that rejects bad ints early.
When it happens
Trigger: Passing --cache-ttl=-1 or --lock-timeout=abc, setting ACTUAL_CACHE_TTL / ACTUAL_LOCK_TIMEOUT to a negative or non-numeric string, or a config file supplying -1 for these keys.
Common situations: Using -1 to mean 'infinite' (unsupported); typos like 3o instead of 30; leaving a stray minus sign in an env var.
Understand the failure class
Background: "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained — this error's family across 35 libraries.
Related errors
- Invalid --name: must be a non-empty string.
- No update fields provided. Use --name or --offbudget.
- Invalid cutoff date: expected a valid date (e.g. YYYY-MM-DD)
- No update fields provided. Use --name or --hidden.
- No update fields provided. Use --name or --hidden.
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/d4d3d2d43adc11b8.
Report an issue: GitHub.