musistudio/claude-code-router · error

ARCHIVE_EXPIRED

ARCHIVE_EXPIRED

Error message

Archive ${archiveId} has expired.

What it means

Thrown by the context archive gateway when replaying an archive whose snapshot expiry timestamp has passed. The archive store keeps snapshots with an optional expiresAt; once Date.now() exceeds it, the snapshot is treated as gone even if the row still exists. It protects stale context from being replayed.

Source

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

    archiveId: string;
    sessionToken: string;
    task: string;
  }, 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;
      }

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Re-create the archive (a new root snapshot) and restart the replay session with the new archiveId
  2. Increase the archive TTL/retention configuration when creating snapshots
  3. Complete replay workflows within the configured expiry window

Example fix

// before
const answer = await archive.ask(archiveId, token, task); // ARCHIVE_EXPIRED

// after
const snap = archive.inspect(archiveId);
if (snap?.expiresAt && snap.expiresAt <= Date.now()) {
  const fresh = await archive.create(/* new root snapshot */);
  archiveId = fresh.archiveId; token = fresh.sessionToken;
}
const answer = await archive.ask(archiveId, token, task);
Defensive patterns

Strategy: validation

Validate before calling

const snap = store.get(archiveId);
if (!snap || (snap.expiresAt !== undefined && snap.expiresAt <= Date.now() + 60_000)) {
  throw new Error('archive expired or expiring imminently — recreate it');
}
await archive.ask(archiveId, sessionToken, task);

Type guard

function isUsableArchive(s: { status: string; expiresAt?: number } | undefined): s is { status: 'ready'; expiresAt?: number } {
  return !!s && s.status === 'ready' && (s.expiresAt === undefined || s.expiresAt > Date.now());
}

Try / catch

try { await archive.ask(id, token, task); }
catch (e) { if (e.code === 'ARCHIVE_EXPIRED') { /* recreate archive, restart session */ } throw e; }

Prevention

When it happens

Trigger: Calling ask(archiveId, sessionToken, ...) after the archive's TTL elapsed — e.g. a job resumed hours later, or the archive was created with a short retention window. The snapshot exists and status is ready, but expiresAt <= Date.now().

Common situations: Long-running pipelines that pause between turns; retention/TTL config set too low for the workflow's wall-clock duration; clock skew between writer and reader.

Related errors


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