musistudio/claude-code-router · error

Artifact URL contains an invalid access token.

Error message

Artifact URL contains an invalid access token.

What it means

The final check in validateCodexMediaArtifactUrl: the URL must carry exactly one query parameter named token whose value matches ^[A-Za-z0-9_-]{32}$ (a 32-char base64url token). Extra params, a missing token, a differently-named param, or wrong length/charset all throw this.

Source

Thrown at packages/core/src/agents/codex/media-preview-bridge.ts:288

  return url.startsWith("app://codex") || url.startsWith("app://chatgpt") || /\b(codex|chatgpt)\b/i.test(target.title || "");
}

function validateCodexMediaArtifactUrl(value: string, endpoint: string): ValidatedArtifactUrl {
  const expected = new URL(endpoint);
  const url = new URL(value);
  if (url.protocol !== "http:" || url.origin !== expected.origin) throw new Error("Artifact origin is not the configured CCR gateway.");
  if (url.username || url.password || url.hash) throw new Error("Artifact URL contains unsupported credentials or fragments.");
  if (!url.pathname.startsWith(MEDIA_ARTIFACT_PATH_PREFIX)) throw new Error("Artifact URL does not use the CCR media artifact path.");
  const encodedId = url.pathname.slice(MEDIA_ARTIFACT_PATH_PREFIX.length);
  if (!encodedId || encodedId.includes("/")) throw new Error("Artifact URL contains an invalid identifier.");
  const artifactId = decodeURIComponent(encodedId);
  if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(artifactId)) {
    throw new Error("Artifact URL contains an invalid identifier.");
  }
  const keys = [...url.searchParams.keys()];
  const token = url.searchParams.get("token") || "";
  if (keys.length !== 1 || keys[0] !== "token" || !/^[A-Za-z0-9_-]{32}$/.test(token)) {
    throw new Error("Artifact URL contains an invalid access token.");
  }
  return { artifactId, url };
}

async function loadCodexMediaArtifact(validated: ValidatedArtifactUrl, signal: AbortSignal): Promise<LoadedMediaArtifact> {
  let response: Response;
  try {
    response = await fetch(validated.url, {
      headers: { accept: "image/*, video/*" },
      redirect: "error",
      signal
    });
  } catch {
    throw new Error("The CCR artifact request failed.");
  }
  if (!response.ok) throw new Error(`The CCR artifact endpoint returned HTTP ${response.status}.`);
  if (response.redirected) throw new Error("The CCR artifact endpoint attempted a redirect.");
  const declaredMimeType = (response.headers.get("content-type") || "").split(";", 1)[0].trim().toLowerCase();

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Ensure the gateway issues the token as exactly 32 base64url characters (no padding) in the sole token query param
  2. Strip any extra query parameters before validating / stop appending them upstream
  3. If the token scheme legitimately changed, align this package's regex or pin compatible versions

Example fix

// before
validateCodexMediaArtifactUrl("http://gw/media/artifact/<uuid>?token=abc&src=cli", endpoint);
// after
validateCodexMediaArtifactUrl("http://gw/media/artifact/<uuid>?token=AbCdEfGhIjKlMnOpQrStUvWxYz012345", endpoint);
Defensive patterns

Strategy: validation

Validate before calling

const u = new URL(artifactUrl);
const keys = [...u.searchParams.keys()];
const token = u.searchParams.get('token') || '';
if (keys.length !== 1 || keys[0] !== 'token' || !/^[A-Za-z0-9_-]{32}$/.test(token)) {
  throw new Error('rejecting artifact with bad token');
}

Type guard

function hasValidArtifactToken(value: string): boolean {
  try { const u = new URL(value); const k = [...u.searchParams.keys()]; const t = u.searchParams.get('token') || ''; return k.length === 1 && k[0] === 'token' && /^[A-Za-z0-9_-]{32}$/.test(t); } catch { return false; }
}

Prevention

When it happens

Trigger: Artifact URL with no ?token=, with additional query params (?token=...&foo=1), a token shorter/longer than 32 chars, or containing characters outside A-Za-z0-9_- (e.g. '+', '=' from standard base64).

Common situations: Token generation changed to standard base64 (with + and =) or a different length; querystring parsers/gateways appending extra params like utm_ or sig; tokens stripped or re-encoded by proxies.

Related errors


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