{"record":{"id":"a1bf144690649f2c","repo":"paperclipai/paperclip","slug":"no-previous-managed-payload-is-available-for-rollb","errorCode":null,"errorMessage":"No previous managed payload is available for rollback.","messagePattern":"No previous managed payload is available for rollback\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/src/commands/update.ts","lineNumber":132,"sourceCode":"  return 0;\n}\n\nexport function resolveUpdateRequest(manifest: InstallManifest | null, options: Pick<UpdateOptions, \"canary\" | \"latest\" | \"version\">): { spec: string; channel: InstallChannel; explicit: boolean } {\n  const selected = Number(Boolean(options.canary)) + Number(Boolean(options.latest)) + Number(Boolean(options.version));\n  if (selected > 1) throw new Error(\"Choose only one of --latest, --canary, or --version.\");\n  if (options.version) return { spec: options.version.trim(), channel: \"pinned\", explicit: true };\n  if (options.canary) return { spec: \"canary\", channel: \"canary\", explicit: true };\n  if (options.latest) return { spec: \"latest\", channel: \"latest\", explicit: true };\n  if (manifest?.channel === \"pinned\") return { spec: manifest.version, channel: \"pinned\", explicit: false };\n  const channel = manifest?.channel === \"canary\" ? \"canary\" : \"latest\";\n  return { spec: channel, channel, explicit: false };\n}\n\nexport function rollbackManagedInstall(paths = resolveInstallStorePaths()): InstallManifest {\n  const manifest = readInstallManifest(paths);\n  if (!manifest) throw new Error(\"No managed install was found to roll back.\");\n  const target = manifest.previous[0];\n  if (!target) throw new Error(\"No previous managed payload is available for rollback.\");\n  if (!fs.existsSync(target.payloadPath)) throw new Error(`Previous payload is missing: ${target.payloadPath}`);\n  const current: InstallRecord = { source: manifest.source, version: manifest.version, channel: manifest.channel, payloadPath: manifest.payloadPath, repo: manifest.repo, ref: manifest.ref, sha: manifest.sha, installedAt: manifest.installedAt };\n  const next: InstallManifest = { schemaVersion: manifest.schemaVersion, ...target, previous: [current, ...manifest.previous.slice(1)].slice(0, 2) };\n  const oldTarget = fs.readlinkSync(paths.currentPath);\n  flipCurrentAtomic(target.payloadPath, paths);\n  try { writeInstallManifestAtomic(next, paths); } catch (error) { flipCurrentAtomic(path.resolve(paths.cliRoot, oldTarget), paths); throw error; }\n  return next;\n}\n\nasync function defaultConfirm(message: string): Promise<boolean> {\n  if (!process.stdin.isTTY || !process.stdout.isTTY) return false;\n  const answer = await p.confirm({ message, initialValue: false });\n  return !p.isCancel(answer) && answer === true;\n}\nfunction emit(options: UpdateOptions, value: Record<string, unknown>, message: string): void { if (options.json) console.log(JSON.stringify(value, null, 2)); else console.log(message); }\n\nasync function rollbackAfterServiceValidationFailure(\n  paths: InstallStorePaths,","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/commands/update.ts#L114-L150","documentation":"Thrown by rollbackManagedInstall when a manifest exists but its `previous` array is empty (manifest.previous[0] is undefined). Rollback swaps the current payload with the most recent prior entry; with no prior payload recorded there is nothing to roll back to. This happens when the current install is the first managed install or all previous entries were pruned.","triggerScenarios":"Running `paperclipai update --rollback` on a freshly installed managed CLI that has only ever had one payload (no prior version). Also if pruneInstallPayloads or manual manifest editing emptied the previous[] array.","commonSituations":"First update attempt immediately after initial install. Manifest hand-edited to clear history. Older payload directories deleted from disk and manifest cleaned up to match.","solutions":["There is no prior payload to restore — reinstall the desired version directly: `paperclipai install --version <semver>` or `paperclipai update --version <semver>`.","Restore a known-good payload directory and prepend it to the manifest's previous[] array, then retry rollback.","Keep at least one update between rollbacks so the previous[] history is populated."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { readInstallStorePaths, readInstallManifest } from '../install-store.js';\nfunction hasPreviousPayload(): boolean {\n  const manifest = readInstallManifest(resolveInstallStorePaths());\n  return Boolean(manifest && manifest.previous.length > 0);\n}\n// if (!hasPreviousPayload()) { /* install desired version directly, no rollback */ }","typeGuard":null,"tryCatchPattern":"try {\n  rollbackManagedInstall(paths);\n} catch (error) {\n  if (error instanceof Error && error.message === 'No previous managed payload is available for rollback.') {\n    // no history — install the target version explicitly instead\n    await updateCommand({ version: desiredVersion, yes: true });\n  } else throw error;\n}","preventionTips":["Perform at least one update so the manifest records a previous entry before relying on rollback.","Avoid editing manifest.previous[] manually; let the installer manage history.","Treat rollback as a convenience, not a backup strategy — keep DB backups too."],"tags":["rollback","managed-install","update"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}