paperclipai/paperclip · error

native_runner_authority_archive_conflict

native_runner_authority_archive_conflict

Error message

native_runner_authority_archive_conflict

What it means

During local authority epoch rotation, the live control-plane directory and runner-state.json are moved (rename) into the newly created epoch archive. If the destination already exists in the archive — meaning an archive entry for these paths is already present — the rotation would clobber a prior archived epoch, so it throws native_runner_authority_archive_conflict. This is a double-rotation / non-idempotent-retry guard.

Source

Thrown at packages/paperclip-runner/src/live/runnerd-codex-transport.ts:332

    throw new Error("native_runner_authority_rotation_requires_settled_state");
  }
  const archivesRoot = resolve(root, "authority-epochs");
  if (existsSync(archivesRoot)) {
    assertRealDirectory(archivesRoot);
  } else {
    mkdirSync(archivesRoot, { mode: 0o700 });
  }
  if (existsSync(archive)) {
    assertRealDirectory(archive);
  } else {
    mkdirSync(archive, { mode: 0o700 });
  }
  assertRealDirectory(archive);
  const activeControlPlane = resolve(root, "control-plane");
  if (existsSync(activeControlPlane)) {
    assertRealDirectory(activeControlPlane);
    if (existsSync(archivedControlPlane)) {
      throw new Error("native_runner_authority_archive_conflict");
    }
    renameSync(activeControlPlane, archivedControlPlane);
  }
  if (existsSync(runnerStatePath)) {
    if (existsSync(archivedRunnerState)) {
      throw new Error("native_runner_authority_archive_conflict");
    }
    renameSync(runnerStatePath, archivedRunnerState);
  }
  if (!existsSync(archivedControlPlane) || !existsSync(archivedRunnerState)) {
    throw new Error("native_runner_authority_archive_incomplete");
  }
  return controlPlaneState;
}

async function rotateExternalAuthorityEpoch(
  root: string,
  controlPlaneState: Record<string, unknown>,

View on GitHub (pinned to 01ad858492)

Solutions

  1. Check the authority-epochs archive: if the prior rotation completed, do not rotate again — resume normally
  2. If a prior rotation died midway, reconcile manually: either move the live control-plane/runner-state into the archive yourself or restore a consistent layout, then resume
  3. Serialize resume/rotation so only one process rotates a given state root at a time (use a lock file)
  4. If archives are stale duplicates, move them aside before retrying, keeping exactly one archive per epoch

Example fix

// before
find data/runner-state/authority-epochs -maxdepth 2   # shows duplicate control-plane entries
// after
mv data/runner-state/authority-epochs/<epoch>/control-plane data/runner-state/authority-epochs/<epoch>/control-plane.conflict-<date>
# reconcile both copies, ensure only one archive entry per epoch, then resume
Defensive patterns

Strategy: try-catch

Validate before calling

import { existsSync } from "node:fs";
function archiveConflictFree(archive: string): boolean {
  return !existsSync(`${archive}/control-plane`) && !existsSync(`${archive}/runner-state.json`);
}

Try / catch

try {
  await transport.resume();
} catch (err) {
  if (err.code === "native_runner_authority_archive_conflict") {
    logger.error("epoch archive already populated; prior rotation partially completed");
    reconcileArchiveThenResume();
  } else throw err;
}

Prevention

When it happens

Trigger: rotateLocalAuthorityEpoch() runs when archivedControlPlane or archivedRunnerState already exists inside the epoch archive while the corresponding live files also exist (retry after a partially completed rotation, or two rotations racing).

Common situations: A previous rotation crashed after creating the archive entry but before clearing live state, then the resume retries rotation; two runner processes resuming the same state root concurrently; operator re-ran rotation manually between attempts.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/151d4483dcae97ea. Report an issue: GitHub.