musistudio/claude-code-router · error

Artifact URL contains an invalid identifier.

Error message

Artifact URL contains an invalid identifier.

What it means

After stripping the artifact path prefix, the remaining path segment must be non-empty and contain no '/'. This throw fires when encodedId is empty (URL ends exactly at the prefix) or when it still contains slash-separated segments (nested path).

Source

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

    await sleep(codexMediaPreviewPollIntervalMs);
  }
  throw new Error(`Codex App CDP page target was not available${lastError ? `: ${redactBridgeError(lastError)}` : "."}`);
}

function isCodexAppPageTarget(target: DevToolsTarget): boolean {
  if (target.type !== "page" || !target.webSocketDebuggerUrl) return false;
  const url = target.url || "";
  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",

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Ensure the URL contains exactly one non-empty id segment after the prefix with no trailing slash
  2. Fix URL construction (template literal/concat) that adds '/' or omits the id
  3. Normalize trailing slashes before validating

Example fix

// before
validateCodexMediaArtifactUrl(`http://gw${MEDIA_ARTIFACT_PATH_PREFIX}${id}/`, endpoint);
// after
validateCodexMediaArtifactUrl(`http://gw${MEDIA_ARTIFACT_PATH_PREFIX}${id}`, endpoint);
Defensive patterns

Strategy: validation

Validate before calling

const path = new URL(artifactUrl).pathname;
const tail = path.slice(MEDIA_ARTIFACT_PATH_PREFIX.length);
if (!tail || tail.includes('/')) throw new Error('bad artifact id segment');

Type guard

function hasSingleIdSegment(value: string, prefix: string): boolean {
  try { const tail = new URL(value).pathname.slice(prefix.length); return tail.length > 0 && !tail.includes('/'); } catch { return false; }
}

Prevention

When it happens

Trigger: Calling validation with a URL like http://gw< prefix > (no id) or http://gw< prefix >abc/extra — a trailing slash after the id produces an empty second segment and encodedId.includes('/') is true.

Common situations: Trailing slash appended by a proxy or string concatenation bug; building the URL with a doubled path segment; template strings that leave the id slot empty.

Related errors


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