xai-org/grok-build · warning

path {:?} is outside the memory directory {:?}

Error message

path {:?} is outside the memory directory {:?}

What it means

MemoryStorage::read_file canonicalizes the requested path and requires it to be inside the canonicalized global memory directory; otherwise it returns this PermissionDenied io::Error. It is a deliberate path-traversal guard so callers cannot read arbitrary files outside memory storage.

Source

Thrown at crates/codegen/xai-grok-memory/src/storage.rs:278

    /// Both the path and the memory root must be canonicalizable; if either fails, the read is rejected.
    pub fn read_file(
        &self,
        path: &Path,
        from: Option<usize>,
        lines: Option<usize>,
    ) -> std::io::Result<String> {
        // Security: canonicalize both sides; fail hard if either doesn't exist
        let canonical = dunce::canonicalize(path)?;
        let canonical_global = dunce::canonicalize(&self.global_dir).map_err(|e| {
            std::io::Error::new(
                std::io::ErrorKind::NotFound,
                format!("memory directory {:?} does not exist: {e}", self.global_dir),
            )
        })?;

        // Fail-closed caveat for paths longer than MAX_PATH: see workspace clippy.toml
        if !canonical.starts_with(&canonical_global) {
            return Err(std::io::Error::new(
                std::io::ErrorKind::PermissionDenied,
                format!(
                    "path {:?} is outside the memory directory {:?}",
                    path, self.global_dir
                ),
            ));
        }

        // Read the canonicalized path, not the original, to prevent TOCTOU races.
        let content = std::fs::read_to_string(&canonical)?;

        let from = from.unwrap_or(0);
        match lines {
            Some(count) => {
                let selected: Vec<&str> = content.lines().skip(from).take(count).collect();
                Ok(selected.join("\n"))
            }
            None if from > 0 => {

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Resolve the requested file relative to the memory directory root and pass a path inside it
  2. Reject/clean ../ segments and canonicalize user input before calling read_file
  3. Remove or re-point symlinks that escape the memory directory
  4. If access outside is intended, configure a different storage root that contains the target

Example fix

// before
let p = std::path::PathBuf::from(user_supplied); // may be ../../etc/passwd
let s = storage.read_file(&p, None, None)?;
// after
let p = memory_root.join(user_supplied);
let p = dunce::canonicalize(&p)?;
assert!(p.starts_with(&memory_root));
let s = storage.read_file(&p, None, None)?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_inside_memory_dir(path: &Path, root: &Path) -> std::io::Result<bool> {
    let c = dunce::canonicalize(path)?;
    let r = dunce::canonicalize(root)?;
    Ok(c.starts_with(r))
}

Type guard

fn safe_memory_path(path: &Path, root: &Path) -> Option<PathBuf> {
    let c = dunce::canonicalize(path).ok()?;
    let r = dunce::canonicalize(root).ok()?;
    if c.starts_with(r) { Some(c) } else { None }
}

Try / catch

match storage.read_file(&path, None, None) {
    Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {
        eprintln!("refusing path outside memory dir: {path:?}");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling read_file with a path containing ../ escapes, a symlink resolving outside the memory root, an absolute path to another location, or a path inside a different profile directory.

Common situations: Constructing file names from user or LLM-supplied input without sanitization; symlinked memory directories; tests asserting rejection (test_storage_read_file_rejects_outside_path).

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


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