musistudio/claude-code-router · error

ARCHIVE_NOT_READY

ARCHIVE_NOT_READY

Error message

Archive ${archiveId} is ${rootSnapshot.status}.

What it means

Thrown when the archive snapshot exists and is unexpired but its status field is anything other than "ready" — typically "pending" or "failed". The gateway refuses to replay a snapshot that never finished persisting or that errored during creation.

Source

Thrown at packages/core/src/gateway/context-archive.ts:229

  }, config: ContextArchiveConfig, executor?: ContextArchiveReplayExecutor): Promise<ContextArchiveAskOutput> {
    const archiveId = input.archiveId.trim();
    const sessionToken = input.sessionToken.trim();
    const task = input.task.trim();
    const toolName = config.toolName || defaultToolName;
    if (!archiveId || !sessionToken || !task) {
      throw contextArchiveError("ARCHIVE_INVALID_ARGUMENT", `${toolName} requires archive_id, session_token, and task.`);
    }

    const store = this.store(config);
    const rootSnapshot = store.get(archiveId);
    if (!rootSnapshot) {
      throw contextArchiveError("ARCHIVE_NOT_FOUND", `Archive ${archiveId} does not exist or has expired.`);
    }
    if (rootSnapshot.expiresAt !== undefined && rootSnapshot.expiresAt <= Date.now()) {
      throw contextArchiveError("ARCHIVE_EXPIRED", `Archive ${archiveId} has expired.`);
    }
    if (rootSnapshot.status !== "ready") {
      throw contextArchiveError("ARCHIVE_NOT_READY", `Archive ${archiveId} is ${rootSnapshot.status}.`);
    }
    if (!constantTimeEqual(rootSnapshot.tokenHash, sha256(sessionToken))) {
      throw contextArchiveError("ARCHIVE_ACCESS_DENIED", "The archive session token is invalid.");
    }
    if (!executor) {
      throw contextArchiveError("ARCHIVE_REPLAY_UNAVAILABLE", "The gateway replay executor is not available.");
    }

    const lineage = store.lineage(archiveId, maxLineageReplayDepth);
    const searchedGenerations: number[] = [];
    let lastInsufficientAnswer: { answer: string; snapshot: ArchiveSnapshot } | undefined;
    for (const snapshot of lineage) {
      if (snapshot.expiresAt !== undefined && snapshot.expiresAt <= Date.now()) {
        continue;
      }
      if (snapshot.status !== "ready") {
        continue;
      }

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Wait for archive creation to fully complete (await the create promise / poll until status === 'ready') before calling ask
  2. If status is 'failed', re-run the archival and generate a new snapshot
  3. Inspect the snapshot record to see which non-ready state it is in and fix the underlying write path

Example fix

// before
await archive.create(request); // not awaited
await archive.ask(archiveId, token, task); // ARCHIVE_NOT_READY

// after
const { archiveId, sessionToken } = await archive.create(request); // fully persisted, status 'ready'
await archive.ask(archiveId, sessionToken, task);
Defensive patterns

Strategy: validation

Validate before calling

const snap = store.get(archiveId);
if (!snap || snap.status !== 'ready') {
  await waitFor(() => store.get(archiveId)?.status === 'ready', { timeout: 30_000 });
}
await archive.ask(archiveId, sessionToken, task);

Type guard

function isReadyArchive(s: { status: string } | undefined): s is { status: 'ready' } {
  return s?.status === 'ready';
}

Try / catch

try { await archive.ask(id, token, task); }
catch (e) { if (e.code === 'ARCHIVE_NOT_READY') { /* poll status, back off, or recreate */ } throw e; }

Prevention

When it happens

Trigger: Calling ask() while the archive is still being written (race: create() has not resolved); replaying a snapshot whose archival step previously failed; status flipped to a non-ready state by a concurrent writer.

Common situations: Fire-and-forget archive creation followed by an immediate replay; crashed archive jobs leaving rows in pending/failed; testing against partially seeded stores.

Related errors


AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27). Data as JSON: /api/errors/94bd0909336668d4. Report an issue: GitHub.