JuliusBrussee/caveman · error
cave_sandbox_credential_capability_ambiguous
cave_sandbox_credential_capability_ambiguous
Error message
cave_sandbox_credential_capability_ambiguous
What it means
Thrown by validateSandboxCredentialEnv() when the requested env names are individually allowlisted but map to more than one provider capability (capabilities.size > 1). The sandbox builds one deterministic child env with exactly one selected provider capability, so mixing credential names from two different providers (e.g. one OpenAI name and one Anthropic name) in one call is ambiguous and refused.
Source
Thrown at packages/agent/src/runtime.ts:606
export function validateSandboxCredentialEnv(names: readonly string[]): void {
const capabilities = new Set<SandboxCredentialCapability>();
for (const name of names) {
const denied = typeof name === "string" &&
(SANDBOX_CREDENTIAL_DENY_NAMES.has(name) ||
SANDBOX_CREDENTIAL_DENY_PREFIXES.some((prefix) => name.startsWith(prefix)));
const capability = denied || typeof name !== "string"
? undefined
: SANDBOX_CREDENTIAL_ENV_TO_CAPABILITY.get(name);
if (capability === undefined) {
// Keep profile-controlled names out of errors. This is a policy result,
// not a diagnostic surface, and the name may itself identify a secret.
throw new Error("cave_sandbox_credential_env_not_allowlisted");
}
capabilities.add(capability);
}
if (capabilities.size > 1) {
throw new Error("cave_sandbox_credential_capability_ambiguous");
}
}
/** Build the complete environment for an isolated tool child. No spread of
* `process.env`: only deterministic runtime baseline plus an exact provider
* capability selected by the validated live profile. */
export function buildSandboxToolEnv(names: readonly string[] = []): NodeJS.ProcessEnv {
validateSandboxCredentialEnv(names);
const env: NodeJS.ProcessEnv = {
LANG: process.env.LANG ?? "C",
LC_ALL: process.env.LC_ALL ?? "C",
PATH: process.env.PATH ?? "",
TZ: process.env.TZ ?? "UTC",
CAVE_EVAL_FIXTURE: "1",
};
for (const name of names) {
const value = process.env[name];
if (value === undefined) throw new Error("cave_sandbox_credential_missing");View on GitHub (pinned to 27d5a3981a)
Solutions
- Split the call: pass only the env names of the single provider the tool run actually uses, one buildSandboxToolEnv call per capability
- Derive the names from one provider's entry in SANDBOX_CREDENTIAL_ENV_BY_CAPABILITY rather than hand-listing
- Group your profile by provider at config time so mixed lists are impossible to construct
Example fix
// before buildSandboxToolEnv([...openAiNames, ...anthropicNames]); // after const openAiEnv = buildSandboxToolEnv(openAiNames); const anthropicEnv = buildSandboxToolEnv(anthropicNames); // separate tool runs
Defensive patterns
Strategy: validation
Validate before calling
function namesShareOneCapability(names: readonly string[]): boolean {
const caps = new Set(names.map((n) => capabilityOf(n)).filter((c) => c !== undefined));
return caps.size <= 1; // capabilityOf mirrors SANDBOX_CREDENTIAL_ENV_TO_CAPABILITY.get
} Try / catch
try { buildSandboxToolEnv(names); } catch (e) { if (e instanceof Error && e.message === 'cave_sandbox_credential_capability_ambiguous') throw new SandboxConfigError('env names span multiple providers; split per provider', { cause: e }); throw e; } Prevention
- Group credential env names by provider in config; never concatenate profiles
- Derive the list from a single provider entry in the capability map
- One buildSandboxToolEnv call = one provider capability
When it happens
Trigger: Calling buildSandboxToolEnv(['<openai-capability-name>', '<anthropic-capability-name>']) — any combination where at least two names resolve to different keys of SANDBOX_CREDENTIAL_ENV_BY_CAPABILITY.
Common situations: Aggregating 'all creds we might need' into one env list; a multi-provider tool profile that forwards every configured provider's variables at once; concatenating two provider profiles during a migration.
Related errors
- cave_sandbox_credential_env_not_allowlisted
- ssrf: credentials embedded in URL are forbidden
- probe returned false
- cave_sandbox_conformance_failed
- cave_live_eval_sandbox_profile_missing
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/4b75038a9618005f.
Report an issue: GitHub.