xai-org/grok-build · error

Custom sandbox profile '{name}' not found. Define it in ~/.g

Error message

Custom sandbox profile '{name}' not found. Define it in ~/.grok/sandbox.toml or .grok/sandbox.toml:

[profiles.{name}]
extends = "workspace"
read_only = ["/data"]

What it means

`ProfileName::resolve` fails when the sandbox configuration references a custom profile by name that is not defined in either ~/.grok/sandbox.toml (user) or .grok/sandbox.toml (workspace). The error is deliberately verbose and instructive: it names the missing profile and shows the exact TOML snippet needed to define it, typically extending a built-in profile with extra read_only paths.

Source

Thrown at crates/codegen/xai-grok-sandbox/src/profiles.rs:477

                    read_write: essential_writable_paths(workspace),
                    deny: vec![],
                    write_deny: resolve_write_deny(self)?,
                    default_read: false,
                    restrict_network: true,
                })
            }

            Self::Custom(name) => {
                let profile_config = config.profiles.get(name).ok_or_else(|| {
                    anyhow::anyhow!(
                        "Custom sandbox profile '{name}' not found. \
                         Define it in ~/.grok/sandbox.toml or .grok/sandbox.toml:\n\n\
                         [profiles.{name}]\n\
                         extends = \"workspace\"\n\
                         read_only = [\"/data\"]\n"
                    )
                })?;

                // Start from the base profile if `extends` is set
                let (base, mut profile) = if let Some(base_name) = &profile_config.extends {
                    let base: ProfileName = base_name.parse().map_err(|e: String| {
                        anyhow::anyhow!("Profile '{name}' extends invalid base: {e}")
                    })?;
                    if matches!(base, Self::Off) {
                        anyhow::bail!(
                            "Profile '{name}' extends '{base_name}', but 'off'/'none' \
                             is not a valid base profile"
                        );
                    }
                    if matches!(base, Self::Custom(_)) {
                        anyhow::bail!(
                            "Profile '{name}' extends '{base_name}', but custom profiles \
                             cannot extend other custom profiles (only built-ins)"
                        );
                    }
                    let resolved = base.resolve(workspace, config)?;

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Create the profile in ~/.grok/sandbox.toml or .grok/sandbox.toml with the exact section name, e.g. [profiles.<name>] with extends and read_only keys.
  2. Check for typos: the name after `profiles.` must exactly match the name used on the CLI/config reference.
  3. Confirm you are running from the workspace root so .grok/sandbox.toml is discovered, or move the definition to ~/.grok/sandbox.toml.
  4. Validate the TOML file parses (e.g. `tomlcheck` or load it in a quick script) — a parse error can make defined profiles invisible.
  5. If you meant a built-in profile, use its exact name instead of a custom one.

Example fix

# before (.grok/sandbox.toml missing the section)
# CLI: --profile data-ro  -> not found
# after
[profiles.data-ro]
extends = "workspace"
read_only = ["/data"]
# CLI: --profile data-ro  -> resolves
Defensive patterns

Strategy: validation

Validate before calling

use std::path::Path;
fn profile_defined(name: &str, workspace: &Path) -> Result<(), String> {
    let candidates = [workspace.join(".grok/sandbox.toml"),
                      dirs::home_dir().map(|h| h.join(".grok/sandbox.toml"))];
    for f in candidates.into_iter().flatten() {
        if !f.exists() { continue; }
        let text = std::fs::read_to_string(&f).map_err(|e| e.to_string())?;
        let toml: toml::Value = text.parse().map_err(|e| format!("{}: {e}", f.display()))?;
        if toml.get("profiles").and_then(|p| p.get(name)).is_some() { return Ok(()); }
    }
    Err(format!("profile '{name}' not found in any sandbox.toml"))
}
// call before resolving the profile

Try / catch

match resolve_profile(&name, workspace) {
    Ok(p) => p,
    Err(e) if e.to_string().contains("not found. Define it in") => {
        eprintln!("{e:#}"); // the error already contains the exact TOML snippet to add
        eprintln!("Or check you are running from the workspace root so .grok/sandbox.toml is found.");
        std::process::exit(2);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: CLI flag or config sets profile = "myprofile" but no [profiles.myprofile] section exists in either config file; the config file exists but in the wrong directory; the section name is misspelled; the file fails to parse so the profile list appears empty.

Common situations: Copying a config snippet from docs but forgetting the [profiles.X] header; expecting workspace .grok/sandbox.toml to be picked up when running outside the repo root; typo between profile name in CLI and section name; TOML syntax error silently invalidating the file.

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/ed4318fa3cc3fb1a. Report an issue: GitHub.