musistudio/claude-code-router · error

Artifact URL contains unsupported credentials or fragments.

Error message

Artifact URL contains unsupported credentials or fragments.

What it means

Part of validateCodexMediaArtifactUrl's strict parsing: the artifact URL must be a bare http URL with no userinfo (username/password) and no #fragment. Any of url.username, url.password, or url.hash being non-empty triggers this throw.

Source

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

    } catch (error) {
      lastError = error;
    }
    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 {

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Strip credentials and fragments from the artifact URL before validation
  2. Fix the upstream generator so it never emits userinfo or fragments in artifact links
  3. If auth is required, deliver it out-of-band (headers/token param) instead of URL credentials

Example fix

// before
validateCodexMediaArtifactUrl("http://gw/media/artifact/...#preview", endpoint);
// after
validateCodexMediaArtifactUrl("http://gw/media/artifact/...", endpoint);
Defensive patterns

Strategy: validation

Validate before calling

const u = new URL(artifactUrl);
if (u.username || u.password || u.hash) artifactUrl = u.origin + u.pathname + (u.search || ''); // sanitize before validating

Type guard

function isBareArtifactUrl(value: string): boolean {
  try { const u = new URL(value); return !u.username && !u.password && !u.hash; } catch { return false; }
}

Prevention

When it happens

Trigger: Passing an artifact URL like http://user:pass@gateway/... or http://gateway/media/...#section — anything containing credentials or a fragment component.

Common situations: URLs copied from browser devtools that include fragments; gateways or proxies that embed basic-auth credentials in the URL; hand-built URL strings that accidentally append '#'.

Related errors


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