{"record":{"id":"cb48fbd6011913d5","repo":"musistudio/claude-code-router","slug":"safetyissue-message","errorCode":null,"errorMessage":"${safetyIssue.message}","messagePattern":"\\$\\{safetyIssue\\.message\\}","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/providers/probe.ts","lineNumber":344,"sourceCode":"    startedAt: check.startedAt,\n    statusCode: protocol?.status ?? (successful ? 200 : 599),\n    url: protocol?.endpoint ?? candidate?.baseUrl ?? \"provider-connectivity-check\"\n  });\n}\n\nfunction providerProbeCandidateName(candidate: GatewayProviderProbeCandidate | undefined): string | undefined {\n  const value: unknown = candidate;\n  return isRecord(value) ? readString(value.name) : undefined;\n}\n\nasync function resolveGatewayProviderProbe(request: GatewayProviderProbeRequest): Promise<GatewayProviderProbeResult> {\n  const mode = request.mode ?? \"protocols\";\n  const safetyIssue = providerApiKeySafetyIssue({\n    apiKey: request.apiKey,\n    baseUrl: request.baseUrl\n  });\n  if (safetyIssue) {\n    throw new Error(safetyIssue.message);\n  }\n\n  const parsed = parseProviderUrl(request.baseUrl);\n  const protocols = providerProbeProtocolsForBaseUrl(request.baseUrl, request.protocols ?? []);\n  const typedModels = uniqueStrings(request.models ?? []);\n  const modelProbe = mode !== \"models\" || request.skipModelDiscovery\n    ? { models: [] }\n    : await probeModels(parsed, request.apiKey, protocols, request.providerPlugins ?? []);\n  const models = (mode === \"connectivity\" || mode === \"models\") && modelProbe.models.length > 0\n    ? modelProbe.models\n    : typedModels;\n  const protocolResults = await probeProtocols(parsed, request.apiKey, models, protocols, mode, request.providerPlugins ?? []);\n  const detectedProtocol = detectProtocol(parsed, protocolResults, modelProbe.source, protocols);\n  const normalizedBaseUrl = detectedProtocol\n    ? resolveProbeBaseUrl(parsed, detectedProtocol, protocolResults, modelProbe)\n    : parsed.normalizedInputBaseUrl;\n  const detectedProvider = detectProvider(protocolResults);\n  const account = detectedProvider === \"new-api\" ? newApiKeyUsageAccountConfig(normalizedBaseUrl) : undefined;","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/providers/probe.ts#L326-L362","documentation":"resolveGatewayProviderProbe runs providerApiKeySafetyIssue on the request's apiKey + baseUrl before probing and rethrows its message. This blocks probes that would send an API key to a host where it does not belong (key/host preset mismatch), preventing accidental credential leakage during probing.","triggerScenarios":"probe() with a baseUrl that does not match the provider preset the apiKey was issued for, or a baseUrl/host combination flagged by providerApiKeySafetyIssue (wrong vendor endpoint, impersonated host).","commonSituations":"Using an Anthropic key against an OpenAI-format base URL, pointing a vendor key at a proxy domain not in the preset's allowlist, or copy-pasting base URLs between provider configs.","solutions":["Match the API key vendor with the base URL preset (e.g. Anthropic key → Anthropic preset URL)","If using a gateway/proxy, configure it under a custom provider preset whose base URL matches, rather than overriding a bundled preset's URL","Double-check for typos in baseUrl (trailing paths, wrong subdomain)","Rotate the key if it was previously sent to the wrong host"],"exampleFix":"// before\nprobe({ apiKey: anthropicKey, baseUrl: \"https://api.openai.com/v1\", protocols: [...] })\n// after\nprobe({ apiKey: openaiKey, baseUrl: \"https://api.openai.com/v1\", protocols: [...] })","handlingStrategy":"try-catch","validationCode":"const issue = providerApiKeySafetyIssue({ apiKey: request.apiKey, baseUrl: request.baseUrl });\nif (issue) throw new Error(issue.message);","typeGuard":null,"tryCatchPattern":"try { await resolveGatewayProviderProbe(request); } catch (e) { if (e instanceof Error && /api key/i.test(e.message)) return { ok: false, reason: 'key-host-mismatch' }; throw e; }","preventionTips":["Keep vendor keys paired with their preset base URLs","Use custom presets for gateways/proxies"],"tags":["api-key","provider-config","security","probe"],"backgroundTag":"credential-target-mismatch","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}