xai-org/grok-build · error

deny glob : empty path segment (a doubled '//' or trailing…

Error message

deny glob {glob:?}: empty path segment (a doubled '//' or trailing '/'); remove the extra slash in sandbox.toml

What it means

validate_deny_glob rejects deny globs containing empty path segments — doubled slashes (`a//b`) or trailing slashes (`a/`) — because globset keeps `//` literal while the macOS regex collapses it, causing cross-platform divergence. Only a single leading `/` (absolute-path anchor) is permitted to be an 'empty' segment.

Solutions

  1. Remove the doubled or trailing slash from the glob in sandbox.toml.
  2. If generating globs programmatically, join path components with a normalizing joiner that collapses separators.
  3. Keep an optional single leading `/` for absolute globs — that is the only allowed empty segment.

Example fix

// before (sandbox.toml)
deny = ["/tmp//secrets/**", "var/log/"]
// after
deny = ["/tmp/secrets/**", "var/log"]
Defensive patterns

Strategy: validation

Validate before calling

fn deny_glob_segments_ok(glob: &str) -> bool {
    glob.split('/').enumerate().all(|(i, seg)| {
        !seg.is_empty() || (i == 0 && glob.starts_with('/'))
    })
}
for g in &deny_globs {
    assert!(deny_glob_segments_ok(g), "empty path segment in deny glob: {g}");
}

Prevention

When it happens

Trigger: A deny glob in sandbox.toml such as `/tmp//x`, `foo/bar/`, or any string where glob.split('/') yields an empty segment that is not the leading absolute-path position.

Common situations: Concatenating path strings in config generation (prefix + `/` + path where path already starts with `/`); hand-edited globs with trailing slashes; template rendering producing doubled separators.

Related errors


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

Appendix: source

Thrown at crates/codegen/xai-grok-sandbox/src/deny/glob.rs:92

/// 2. Compile through `globset` (the Linux matcher) so a malformed glob (`a**b`,
///    unterminated `[`) fails closed identically on both platforms.
#[cfg(all(feature = "enforce", unix))]
pub(crate) fn validate_deny_glob(glob: &str) -> anyhow::Result<()> {
    if let Some(c) = glob.chars().find(|&c| matches!(c, '{' | '}' | '\\')) {
        anyhow::bail!(
            "deny glob {glob:?} uses unsupported metacharacter '{c}' \
             (brace alternation and backslash-escapes are not supported; \
             use separate deny entries)"
        );
    }
    // `**` must be a whole path component (gitignore semantics). A non-component
    // `**` (e.g. `a**b`) would translate to `.*` on macOS but collapse to `*` in
    // globset — reject it on both platforms so they never diverge. Empty
    // segments (`a//*`) drift the same way: globset keeps `//` literally while
    // the macOS regex collapses it.
    for (index, segment) in glob.split('/').enumerate() {
        if segment.is_empty() && !(index == 0 && glob.starts_with('/')) {
            anyhow::bail!(
                "deny glob {glob:?}: empty path segment (a doubled '//' or \
                 trailing '/'); remove the extra slash in sandbox.toml"
            );
        }
        // `.`/`..` would let a relative glob scan outside the workspace on
        // Linux while the macOS regex stays dead; reject on both platforms.
        if segment == "." || segment == ".." {
            anyhow::bail!(
                "deny glob {glob:?}: `.` and `..` segments are not supported; \
                 write the path without them (use an absolute path to deny \
                 files outside the workspace)"
            );
        }
        if segment.contains("**") && segment != "**" {
            anyhow::bail!(
                "deny glob {glob:?}: `**` must be its own path segment (got {segment:?}); \
                 write it as `**/` or `/**`, e.g. `a/**/b`"
            );

View on GitHub (pinned to bc7f02eddd)