nexu-io/open-design · error · AuthorizedTeamProjectPullReceiptExpiredError

AUTHORIZED_TEAM_PROJECT_PULL_RECEIPT_EXPIRED

AUTHORIZED_TEAM_PROJECT_PULL_RECEIPT_EXPIRED

Error message

authorized pull receipt is stale

What it means

Thrown as AuthorizedTeamProjectPullReceiptExpiredError (code AUTHORIZED_TEAM_PROJECT_PULL_RECEIPT_EXPIRED, detected via isAuthorizedTeamProjectPullReceiptExpired) when the current time (nowMs, default Date.now()) has passed the receipt's expiresAt. This is the typed, retryable expiry path, distinct from the plain Error 'authorized pull receipt is stale' at line 177 which covers malformed dates or an authorization window longer than RECEIPT_MAX_AGE_MS (2s). The receipt is a short-lived bearer of authorization and must be consumed promptly.

Source

Thrown at apps/daemon/src/collab/authorized-team-project-pull.ts:180

    !MANIFEST_DIGEST_PATTERN.test(receipt.manifestDigest) ||
    receipt.lifecycleState !== 'active' ||
    receipt.ownerMemberId === receipt.viewerMemberId
  ) {
    throw new Error('authorized pull receipt binding is incomplete');
  }
  const authorizedAt = Date.parse(receipt.authorizedAt);
  const expiresAt = Date.parse(receipt.expiresAt);
  const nowMs = input.nowMs ?? Date.now();
  if (
    !Number.isFinite(authorizedAt) ||
    !Number.isFinite(expiresAt) ||
    expiresAt <= authorizedAt ||
    expiresAt - authorizedAt > RECEIPT_MAX_AGE_MS
  ) {
    throw new Error('authorized pull receipt is stale');
  }
  if (nowMs >= expiresAt) {
    throw new AuthorizedTeamProjectPullReceiptExpiredError(
      'authorized pull receipt is stale',
    );
  }
}

export function isAuthorizedTeamProjectPullUnavailable(
  error: unknown,
): boolean {
  const message = error instanceof Error ? error.message : String(error);
  return /unknown command ["']?pull["']?.*team-projects/iu.test(message) ||
    /unknown command ["']?team-projects["']?/iu.test(message) ||
    /unknown flag:\s*--(?:expected-version|live-dir|ref|json)\b/iu.test(message);
}

/** The packaged CLI predates `team-projects pull --authorize-only` (or lacks
 *  `team-projects pull` entirely). Callers must fail OPEN — pull as before —
 *  never block materialization on a missing probe. */
export function isAuthorizedTeamProjectPullInspectUnavailable(

View on GitHub (pinned to 5be4028344)

Solutions

  1. Re-request a fresh authorized pull — do not retry with the same receipt.
  2. Sync the system clock (NTP) on both the authorizer and the daemon to remove skew.
  3. Ensure the pull happens immediately after authorization; remove artificial delays or long queues.
  4. Detect this case with isAuthorizedTeamProjectPullReceiptExpired(error) and trigger re-authorization in the caller.
Defensive patterns

Strategy: retry

Validate before calling

// Re-authorize when the receipt would already be expired by the time it is consumed.
function receiptWillBeFresh(receipt: { authorizedAt: string; expiresAt: string }, now = Date.now()): boolean {
  const expiresAt = Date.parse(receipt.expiresAt);
  return Number.isFinite(expiresAt) && now < expiresAt;
}

Type guard

import { isAuthorizedTeamProjectPullReceiptExpired } from './authorized-team-project-pull.js';
// isAuthorizedTeamProjectPullReceiptExpired(error) is the provided guard

Try / catch

try {
  await runAuthorizedPull(args, workspaceId, options);
} catch (err) {
  if (isAuthorizedTeamProjectPullReceiptExpired(err)) {
    // re-request a fresh authorized pull — never reuse the stale receipt
    await runAuthorizedPull(args, workspaceId, options);
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Clock skew between the machine that authorized the pull and the daemon consuming it, processing latency or a paused/debugged process that exceeded the receipt's lifetime, or a replay attempt using an old receipt.

Common situations: System clock drift, a debugger breakpoint held the process past expiry, a queued/retried pull using a stale receipt, or heavy load stretching the authorize-to-pull gap beyond the 2-second window.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/fcbd93aa2eb8b7a2. Report an issue: GitHub.