Hmbown/CodeWhale · error
patch path must be workspace-relative
Error message
patch path must be workspace-relative
What it means
The path after `*** Update File:` must stay inside the eval workspace: any occurrence of `..` in the relative path is rejected before the file is read (eval.rs:690). This is the sandbox-escape guard for patch targets.
Source
Thrown at crates/tui/src/eval.rs:690
content.push_str(line);
content.push('\n');
fs::write(path, content).with_context(|| format!("failed to write {}", path.display()))
}
fn apply_patch(root: &Path, patch: &str) -> Result<()> {
let mut lines = patch.lines();
let begin = lines.next().unwrap_or_default();
if begin != "*** Begin Patch" {
return Err(anyhow!("patch missing *** Begin Patch header"));
}
let header = lines.next().unwrap_or_default();
let file_rel = header
.strip_prefix("*** Update File: ")
.ok_or_else(|| anyhow!("only *** Update File patches are supported"))?;
if file_rel.contains("..") {
return Err(anyhow!("patch path must be workspace-relative"));
}
let file_path = root.join(file_rel);
let original = read_workspace_file(&file_path)?;
let had_trailing_newline = original.ends_with('\n');
let mut file_lines: Vec<String> = original.lines().map(|l| l.to_string()).collect();
let mut cursor = 0usize;
for raw_line in lines {
if raw_line == "*** End Patch" {
break;
}
if raw_line.starts_with("*** ") {
return Err(anyhow!("unexpected patch directive: {raw_line}"));
}
if raw_line.starts_with("@@") {
continue;
}View on GitHub (pinned to 8880682c63)
Solutions
- Move the target file inside the workspace, or reconfigure the eval root so the target is contained
- Emit a path relative to the workspace root with no parent-directory segments
Example fix
*** before *** Update File: ../shared/config.toml *** after (root the workspace one level up, or reference an in-workspace copy) *** Update File: shared/config.toml
Defensive patterns
Strategy: validation
Validate before calling
let rel = header
.strip_prefix("*** Update File: ")
.context("not an update directive")?;
anyhow::ensure!(!rel.contains(".."), "patch escapes workspace: {rel}"); Type guard
fn patch_path_is_in_workspace(rel: &str) -> bool {
!rel.contains("..")
} Prevention
- Tell the model every path is workspace-relative
- Keep the sandbox root equal to the directory tree the model sees
- Reject parent traversal at the tool boundary before applying
When it happens
Trigger: The patch references `../outside.txt`, `a/../../b`, or any parent traversal; the model tries to edit a file that lives above the eval workspace root.
Common situations: Model reasons about absolute repo paths and emits them as relative paths with `..`; eval root configured one level below the files the model was shown.
Related errors
- Invalid sandbox_mode '{mode}': expected read-only, workspace
- reviewed plugin stdio cwd escaped its staged root
- ${manifestName} checksum mismatch for ${name}
- Codewhale terminal receipt sandbox did not match launch
- budget baseline_receipt path changed
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/5ce29c8a96d86a60.
Report an issue: GitHub.