JuliusBrussee/caveman · error · Error

cave_sandbox_credential_capability_ambiguous

cave_sandbox_credential_capability_ambiguous

Error message

cave_sandbox_credential_capability_ambiguous

What it means

validateSandboxCredentialEnv maps each requested credential env name to a provider capability; if the set of names spans more than one distinct capability, the request is ambiguous about which provider's credential to inject and is rejected.

Solutions

  1. Request credential env vars for exactly one provider capability per sandbox env.
  2. Split the sandbox tool run into separate runs per provider.
  3. Prune unneeded credential names from the profile.
  4. Verify the capability mapping by reading which env names map to which capability in the library.

Example fix

// before
credentialEnv: ["ANTHROPIC_API_KEY", "OPENAI_API_KEY"]; // two capabilities
// after
credentialEnv: ["ANTHROPIC_API_KEY"];
Defensive patterns

Strategy: validation

Validate before calling

const caps = new Set(names.map((n: string) => SANDBOX_CREDENTIAL_ENV_TO_CAPABILITY.get(n)));
if (caps.size > 1) throw new Error("credential env spans multiple provider capabilities");

Type guard

const isSingleCapability = (names: string[]): boolean =>
  new Set(names.map((n: string) => SANDBOX_CREDENTIAL_ENV_TO_CAPABILITY.get(n))).size <= 1;

Try / catch

try {
  buildSandboxToolEnv(names);
} catch (e) {
  if (e.message === "cave_sandbox_credential_capability_ambiguous") {
    // split names by capability and run per provider
  } else throw e;
}

Prevention

When it happens

Trigger: A sandbox profile or buildSandboxToolEnv call requests credential env vars that map to two different provider capabilities (e.g. both an Anthropic key and an OpenAI key) in a single sandbox tool environment.

Common situations: Copy-pasting a profile and leaving credentials for two providers; merging profiles without pruning credential env lists; a shared team profile that accumulated multiple providers' keys.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/4b75038a9618005f. Report an issue: GitHub.

Appendix: 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 3ee70a1026)