musistudio/claude-code-router · error · Error
ZCode profiles can only open the app; agent arguments are no
Error message
ZCode profiles can only open the app; agent arguments are not supported.
What it means
Thrown by parseWebContentFetchResult when the provider's account endpoint responds 2xx but the Content-Type (or body sniffing) does not look like JSON. This is part of the OAuth/account-linking flow where an expected JSON account info endpoint instead returns HTML or another content type.
Source
Thrown at packages/cli/src/cli.ts:122
await runWebServer(options);
return;
}
const profileOptions = options as ProfileCliOptions;
if (profileOptions.help || !profileOptions.profileRef) {
printHelp(profileOptions.help ? 0 : 2);
return;
}
const configDir = CONFIGDIR;
const config = await loadAppConfig();
assertAvailableGatewayModels(config);
await applyProfileConfig(config);
const profile = findProfileForOpen(config, profileOptions.profileRef);
const surface = profileOptions.surface ?? defaultProfileOpenSurface(profile);
const resolvedSurface = resolveProfileOpenSurface(profile, surface);
if (profile.agent === "zcode" && profileOptions.agentArgs.length > 0) {
throw new Error("ZCode profiles can only open the app; agent arguments are not supported.");
}
if (profile.agent === "claude-design") {
throw new Error("Claude Design profiles can only be opened from CCR Desktop.");
}
if (profile.agent === "claude-code" && resolvedSurface === "app" && profileOptions.agentArgs.length > 0) {
throw new Error("Claude App profiles do not support agent arguments.");
}
if (profile.agent === "codex" && resolvedSurface === "app" && profileOptions.agentArgs.length === 0) {
const state = await startService({
command: "start",
daemonChild: false,
ensureGatewayRunning: true,
help: false,
open: false,
profileManaged: false,
startGateway: true
});
const opened = await callServiceRpc<ProfileOpenResult>(state, "openProfile", [{ profileId: profile.id, surface: "app" }], 30_000);View on GitHub (pinned to 99f24806c6)
Solutions
- Verify the account endpoint URL actually returns JSON (curl -i it and check Content-Type)
- If a proxy/portal intercepts the request, fix network config or add required auth headers/cookies
- If the endpoint legitimately returns non-JSON, correct the configured account URL in the provider settings
- Check response body via readableResponseSnippet path/logging to see what was actually returned (HTML login page, XML, empty)
Example fix
// before accountUrl: "https://provider.example.com/account" // returns HTML // after accountUrl: "https://provider.example.com/api/user" // returns application/json
Defensive patterns
Strategy: try-catch
Validate before calling
const looksJson = (ct?: string, text?: string) =>
(ct ?? '').toLowerCase().includes('json') || /^\s*[\[{]/.test(text ?? '');
if (!result.ok || !looksJson(result.contentType, result.text)) {
// fall back to UI-driven account linking instead of parsing
} Type guard
function isJsonFetchResult(result: FetchResult): boolean {
return result.ok && responseLooksJson(result.contentType ?? '',
typeof result.text === 'string' ? result.text : '');
} Try / catch
try {
const data = await parseWebContentFetchResult(result);
} catch (error) {
if (error instanceof Error && error.message.startsWith('Account endpoint returned non-JSON')) {
// endpoint served HTML/text: guide user to manual account entry
} else { throw error; }
} Prevention
- Validate Content-Type before parsing account endpoint responses
- Pre-flight the account URL with a HEAD/GET check during provider add
- Log the content type and a body snippet whenever this fails to identify portal/proxy pages
When it happens
Trigger: Calling the account endpoint via createProviderAccountWebContentFetchHandler, the HTTP request succeeds (result.ok), but responseLooksJson() fails: contentType lacks 'json' and the body doesn't parse/sniff as JSON (e.g. text/html login page, plain text, empty body).
Common situations: Endpoint URL misconfigured to a human-facing page; a captive portal or reverse proxy serving an HTML error/consent page; the provider's account URL requires session cookies the fetch doesn't carry; server returns XML or plain text instead of JSON.
Related errors
- Claude Design profiles can only be opened from CCR Desktop.
- Claude App profiles do not support agent arguments.
- Failed to open Claude App: ${spawnError}
- Failed to open ZCode App: ${spawnError}
- Unable to load @the-next-ai/bot-gateway-sdk. ${errors.join("
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/9bdccb9ffe5f3656.
Report an issue: GitHub.