paperclipai/paperclip · critical

${payloadLabel} failed service validation and was rolled bac

Error message

${payloadLabel} failed service validation and was rolled back to ${rolledBack.version}, but the rolled-back service also failed to restart.

What it means

Thrown by rollbackAfterServiceValidationFailure when, after a newly updated payload fails to start its service, the automatic rollback to the prior version is performed but restarting the rolled-back service also throws. This is the worst-case recovery failure: both the new and the old payload are unable to run the service. The error bundles both the original validation error and the restart error in an AggregateError as `cause`.

Source

Thrown at cli/src/commands/update.ts:159

async function defaultConfirm(message: string): Promise<boolean> {
  if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
  const answer = await p.confirm({ message, initialValue: false });
  return !p.isCancel(answer) && answer === true;
}
function emit(options: UpdateOptions, value: Record<string, unknown>, message: string): void { if (options.json) console.log(JSON.stringify(value, null, 2)); else console.log(message); }

async function rollbackAfterServiceValidationFailure(
  paths: InstallStorePaths,
  restartActiveService: (expectedVersion: string) => Promise<boolean>,
  validationError: unknown,
  payloadLabel: string,
): Promise<never> {
  const rolledBack = await withInstallStoreLock(async () => rollbackManagedInstall(paths), paths);
  try {
    await restartActiveService(rolledBack.version);
  } catch (restartError) {
    throw new Error(
      `${payloadLabel} failed service validation and was rolled back to ${rolledBack.version}, but the rolled-back service also failed to restart.`,
      { cause: new AggregateError([validationError, restartError]) },
    );
  }
  throw new Error(`${payloadLabel} failed service validation and was rolled back to ${rolledBack.version}.`, { cause: validationError });
}

export async function updateCommand(options: UpdateOptions, overrides: Partial<Dependencies> = {}): Promise<void> {
  const paths = overrides.paths ?? resolveInstallStorePaths();
  const executablePath = overrides.executablePath ?? process.argv[1] ?? "";
  const runCommand = overrides.runCommand ?? execFileAsync;
  const mode = detectInstallMode(executablePath, paths);
  const manifest = readInstallManifest(paths);
  if (options.rollback) {
    if (mode !== "managed") throw new Error("--rollback is only available for managed installs.");
    if (options.dryRun) { emit(options, { mode, action: "rollback", dryRun: true, target: manifest?.previous[0]?.version ?? null }, `Would roll back to ${manifest?.previous[0]?.version ?? "the previous payload"}.`); return; }
    const next = await withInstallStoreLock(async () => rollbackManagedInstall(paths), paths);
    const restarted = await (overrides.restartActiveService ?? restartActiveManagedService)(next.version);

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Inspect the AggregateError cause: both the original validation error and the restart error tell you what is broken system-wide (fix that root cause first).
  2. Start the database/service manager and confirm the service unit is loadable: `systemctl --user status paperclipai*` / `launchctl list | grep paperclip`.
  3. Restore the pre-update database backup if the failure is schema/migration related (the old binary cannot start against the migrated DB).
  4. Manually point the `current` symlink at a known-good payload and `paperclipai service restart`, or reinstall with `paperclipai install`.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await updateCommand(options);
} catch (error) {
  if (error instanceof Error && error.message.includes('rolled-back service also failed to restart') && error.cause instanceof AggregateError) {
    const [validationErr, restartErr] = error.cause.errors;
    // both versions are broken — surface both, restore DB backup, and reinstall a known-good payload
    console.error('Validation failure:', validationErr);
    console.error('Restart failure:', restartErr);
    await restorePreUpdateBackup();
    await installCommand({ version: knownGoodVersion });
  } else throw error;
}

Prevention

When it happens

Trigger: An update (git or npm payload) installs successfully, restartActiveManagedService throws on the new version, rollbackAfterServiceValidationFailure rolls back to manifest.previous[0], and the restart call for that rolled-back version throws too. Reached via the catch blocks around lines 203-211 and 257-265 in updateCommand.

Common situations: System-wide breakage affecting all versions — e.g. systemd/launchd itself broken, port conflict on every version, shared DB schema already migrated and incompatible with the old binary, or corrupted payload directories for both versions.

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/0314126c665aa35e. Report an issue: GitHub.