{"record":{"id":"1373330e7f35b1f6","repo":"paperclipai/paperclip","slug":"invalid-retention-days-string-candidate-use","errorCode":null,"errorMessage":"Invalid retention days '${String(candidate)}'. Use a positive integer.","messagePattern":"Invalid retention days '(.+?)'\\. Use a positive integer\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/commands/db-backup.ts","lineNumber":40,"sourceCode":"  const envUrl = process.env.DATABASE_URL?.trim();\n  if (envUrl) return { value: envUrl, source: \"DATABASE_URL\" };\n\n  const config = readConfig(configPath);\n  if (config?.database.mode === \"postgres\" && config.database.connectionString?.trim()) {\n    return { value: config.database.connectionString.trim(), source: \"config.database.connectionString\" };\n  }\n\n  const port = config?.database.embeddedPostgresPort ?? 54329;\n  return {\n    value: `postgres://paperclip:paperclip@127.0.0.1:${port}/paperclip`,\n    source: `embedded-postgres@${port}`,\n  };\n}\n\nfunction normalizeRetentionDays(value: number | undefined, fallback: number): number {\n  const candidate = value ?? fallback;\n  if (!Number.isInteger(candidate) || candidate < 1) {\n    throw new Error(`Invalid retention days '${String(candidate)}'. Use a positive integer.`);\n  }\n  return candidate;\n}\n\nfunction resolveBackupDir(raw: string): string {\n  return path.resolve(expandHomePrefix(raw.trim()));\n}\n\nexport async function dbBackupCommand(opts: DbBackupOptions): Promise<void> {\n  printPaperclipCliBanner();\n  p.intro(pc.bgCyan(pc.black(\" paperclip db:backup \")));\n\n  const configPath = resolveConfigPath(opts.config);\n  const config = readConfig(opts.config);\n  const connection = resolveConnectionString(opts.config);\n  const defaultDir = resolveDefaultBackupDir(resolvePaperclipInstanceId());\n  const configuredDir = opts.dir?.trim() || config?.database.backup.dir || defaultDir;\n  const backupDir = resolveBackupDir(configuredDir);","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/commands/db-backup.ts#L22-L58","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n--retention-days 0\n// after\n--retention-days 30","handlingStrategy":"validation","validationCode":"function isValidRetentionDays(value: number | undefined, fallback: number): boolean {\n  const candidate = value ?? fallback;\n  return Number.isInteger(candidate) && candidate >= 1;\n}\n\nif (!isValidRetentionDays(opts.retentionDays, fallback)) {\n  console.error('retention-days must be a positive integer >= 1.');\n  process.exit(1);\n}","typeGuard":"function isPositiveInteger(value: unknown): value is number {\n  return typeof value === \"number\" && Number.isInteger(value) && value >= 1;\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["cli","argument-validation","db-backup","retention"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}