paperclipai/paperclip · error · Error
Invalid retention days '${String(candidate)}'. Use a positiv
Error message
Invalid retention days '${String(candidate)}'. Use a positive integer. What it means
Thrown by normalizeRetentionDays (db-backup.ts:40) when the resolved retention value is not a positive integer. Used by the db:backup command to compute how many days of backups to keep; the candidate is the explicit option or the configured fallback.
Source
Thrown at cli/src/commands/db-backup.ts:40
const envUrl = process.env.DATABASE_URL?.trim();
if (envUrl) return { value: envUrl, source: "DATABASE_URL" };
const config = readConfig(configPath);
if (config?.database.mode === "postgres" && config.database.connectionString?.trim()) {
return { value: config.database.connectionString.trim(), source: "config.database.connectionString" };
}
const port = config?.database.embeddedPostgresPort ?? 54329;
return {
value: `postgres://paperclip:paperclip@127.0.0.1:${port}/paperclip`,
source: `embedded-postgres@${port}`,
};
}
function normalizeRetentionDays(value: number | undefined, fallback: number): number {
const candidate = value ?? fallback;
if (!Number.isInteger(candidate) || candidate < 1) {
throw new Error(`Invalid retention days '${String(candidate)}'. Use a positive integer.`);
}
return candidate;
}
function resolveBackupDir(raw: string): string {
return path.resolve(expandHomePrefix(raw.trim()));
}
export async function dbBackupCommand(opts: DbBackupOptions): Promise<void> {
printPaperclipCliBanner();
p.intro(pc.bgCyan(pc.black(" paperclip db:backup ")));
const configPath = resolveConfigPath(opts.config);
const config = readConfig(opts.config);
const connection = resolveConnectionString(opts.config);
const defaultDir = resolveDefaultBackupDir(resolvePaperclipInstanceId());
const configuredDir = opts.dir?.trim() || config?.database.backup.dir || defaultDir;
const backupDir = resolveBackupDir(configuredDir);View on GitHub (pinned to 67001ec6eb)
Solutions
- Pass a positive integer: --retention-days 30.
- Fix config: set database.backup.retentionDays to an integer >= 1.
- If you want to keep all backups, pick a very large integer rather than 0 or negative.
Example fix
// before --retention-days 0 // after --retention-days 30
Defensive patterns
Strategy: validation
Validate before calling
function isValidRetentionDays(value: number | undefined, fallback: number): boolean {
const candidate = value ?? fallback;
return Number.isInteger(candidate) && candidate >= 1;
}
if (!isValidRetentionDays(opts.retentionDays, fallback)) {
console.error('retention-days must be a positive integer >= 1.');
process.exit(1);
} Type guard
function isPositiveInteger(value: unknown): value is number {
return typeof value === "number" && Number.isInteger(value) && value >= 1;
} Prevention
- Pass a positive integer for --retention-days.
- Keep config database.backup.retentionDays as an integer >= 1.
- Do not use 0 or negatives to mean 'keep forever'; use a large integer instead.
When it happens
Trigger: Passing --retention-days 0, a negative number, a non-integer like 2.5, or having a config/database.backup.retentionDays that is misconfigured. The guard requires Number.isInteger AND >= 1.
Common situations: Env/config drift where retention was set to 0 to 'disable' pruning (this command does not support that), or a decimal days value from a calculation.
Related errors
- Invalid --adapter-override "${raw}". Use slug=type.
- Invalid ${flag} "${raw}". Use ${format}.
- Agent reference is required
- Invalid --expires-at value: ${opts.expiresAt}
- Invalid --ttl-days value: ${opts.ttlDays}
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/1373330e7f35b1f6.
Report an issue: GitHub.