Sibling bug to msg 7a95e4e8 / GH#225 (BashExec storm) found while investigating executor-adapter token-blowup. After fixing the BashExec routing, the FILE tools (Read/Write) still fail because of a separate path-validation issue.
REPRO (from real session JSONL session_gcd_lcm_b3e9cc16.jsonl, executor adapter, 2026-05-08):
- WORKDIR = /var/folders/kv/.../T/ailang_eval/gcd_lcm_motoko-claude-haiku-4-5_.../gcd_lcm_ailang_motoko_64124
- Agent attempts: ReadFile("/var/folders/kv/.../gcd_lcm_ailang_motoko_64124/benchmark/solution.ail")
- Result: { error: true, message: "absolute paths are not allowed: /var/folders/kv/..." }
- 7 of 10 tool calls in that run failed identically; 3 BashExec calls hit the separate ohmy_pi storm.
The path IS under WORKDIR (the prefix matches exactly). The agent treats the workdir as an absolute path because that's what it received via the WORKDIR env var. So it constructs absolute paths and gets rejected.
ROOT CAUSE:
src/core/tool_runtime.ail:327 in validate_path_common:
else if is_absolute_path(path) then Err(path_error(id, tool, "absolute paths are not allowed: ${path}"))
is_absolute_path is just startsWith(path, "/"). The check is done BEFORE any workdir-containment check. The intent (per the surrounding comments and the wd_bare logic right after) is to prevent path-doubling when the model emits a 'Users/mark/...' style bare-absolute path. But it inadvertently catches the legitimate case where the model emits a /tmp/... or /var/folders/... path that's genuinely inside an absolute workdir.
Distinction from the existing m-motoko-path-doubling-v2 design doc: that doc covers the bare-absolute case (model drops leading slash). This is the OPPOSITE: model includes the leading slash and the path is genuinely an absolute that lives under WORKDIR. wd_bare logic doesn't help because the path already has the slash; the is_absolute_path branch fires first and short-circuits.
WHY THIS BLOCKS executor-adapter (and any benchmark/eval harness):
Most evaluators create per-task temp dirs under /tmp or /var/folders/ and pass that as the WORKDIR. They cannot use a relative path because they don't know the agent's CWD. The agent, seeing the absolute WORKDIR, naturally constructs absolute paths under it — which is what bash, every CLI tool, and most LLMs do by default. Forcing relative-only is a strong constraint that doesn't hold across embedding contexts.
PROPOSED FIX (~10 LOC):
Before the blanket is_absolute_path rejection, check if the path is genuinely under workdir. If so, strip the workdir prefix and proceed as if it were relative:
func validate_path_common(tool: string, id: string, path: string, workdir: string) -> Result[(), ToolResultItem] ! {Process} {
if path == "" then Err(...)
else {
let normalized_path =
if is_absolute_path(path) && workdir != "" && startsWith(path, "${workdir}/")
then substring(path, length(workdir) + 1, length(path))
else if is_absolute_path(path) && path == workdir
then "."
else path;
if is_absolute_path(normalized_path) then Err(...absolute paths are not allowed...)
else if has_parent_traversal_segment(normalized_path) then Err(...)
else { ... existing logic with normalized_path ... }
}
}
Plus extend validate_path_common's contract to require workdir is itself absolute (or empty). Z3 contract: requires { length(path) > 0 } ensures { result == Ok(()) implies !is_absolute_path(stripped_path) }.
ALTERNATIVE: a settings.allow_absolute_paths_under_workdir flag (default true). Operators who explicitly want relative-only can opt out.
WHY P1 NOT P0: msg 7a95e4e8 was P0 because it broke a hello-world fizzbuzz. This bug is P1 because it ONLY breaks evaluators with absolute WORKDIRs — interactive use (where WORKDIR is typically the project root and the model uses relative paths) still works. But for the M-MOTOKO-EXECUTOR-ADAPTER autonomous-eval story, this is structurally blocking.
Filing as bug. Happy to author the patch + a contract-verified test if useful — the change is small and the fix-shape is clear.
Binary info (auto-attached):
ailang version: v0.17.0-46-g7cd0c743-dirty
binary md5: b3402e190334480662a76ed841e341de
binary path: /Users/mark/go/bin/ailang
git commit: 7cd0c74
Reported by: motoko_explore via ailang messages
Sibling bug to msg 7a95e4e8 / GH#225 (BashExec storm) found while investigating executor-adapter token-blowup. After fixing the BashExec routing, the FILE tools (Read/Write) still fail because of a separate path-validation issue.
REPRO (from real session JSONL session_gcd_lcm_b3e9cc16.jsonl, executor adapter, 2026-05-08):
The path IS under WORKDIR (the prefix matches exactly). The agent treats the workdir as an absolute path because that's what it received via the WORKDIR env var. So it constructs absolute paths and gets rejected.
ROOT CAUSE:
src/core/tool_runtime.ail:327 in validate_path_common:
is_absolute_path is just startsWith(path, "/"). The check is done BEFORE any workdir-containment check. The intent (per the surrounding comments and the wd_bare logic right after) is to prevent path-doubling when the model emits a 'Users/mark/...' style bare-absolute path. But it inadvertently catches the legitimate case where the model emits a /tmp/... or /var/folders/... path that's genuinely inside an absolute workdir.
Distinction from the existing m-motoko-path-doubling-v2 design doc: that doc covers the bare-absolute case (model drops leading slash). This is the OPPOSITE: model includes the leading slash and the path is genuinely an absolute that lives under WORKDIR. wd_bare logic doesn't help because the path already has the slash; the is_absolute_path branch fires first and short-circuits.
WHY THIS BLOCKS executor-adapter (and any benchmark/eval harness):
Most evaluators create per-task temp dirs under /tmp or /var/folders/ and pass that as the WORKDIR. They cannot use a relative path because they don't know the agent's CWD. The agent, seeing the absolute WORKDIR, naturally constructs absolute paths under it — which is what bash, every CLI tool, and most LLMs do by default. Forcing relative-only is a strong constraint that doesn't hold across embedding contexts.
PROPOSED FIX (~10 LOC):
Before the blanket is_absolute_path rejection, check if the path is genuinely under workdir. If so, strip the workdir prefix and proceed as if it were relative:
Plus extend validate_path_common's contract to require workdir is itself absolute (or empty). Z3 contract: requires { length(path) > 0 } ensures { result == Ok(()) implies !is_absolute_path(stripped_path) }.
ALTERNATIVE: a settings.allow_absolute_paths_under_workdir flag (default true). Operators who explicitly want relative-only can opt out.
WHY P1 NOT P0: msg 7a95e4e8 was P0 because it broke a hello-world fizzbuzz. This bug is P1 because it ONLY breaks evaluators with absolute WORKDIRs — interactive use (where WORKDIR is typically the project root and the model uses relative paths) still works. But for the M-MOTOKO-EXECUTOR-ADAPTER autonomous-eval story, this is structurally blocking.
Filing as bug. Happy to author the patch + a contract-verified test if useful — the change is small and the fix-shape is clear.
Binary info (auto-attached):
ailang version: v0.17.0-46-g7cd0c743-dirty
binary md5: b3402e190334480662a76ed841e341de
binary path: /Users/mark/go/bin/ailang
git commit: 7cd0c74
Reported by: motoko_explore via ailang messages