Summary
SandboxBackedFilesystem.uploadFiles(...) mirrors files into the Docker sandbox by base64-encoding the whole file content and embedding it as a single argument of a docker exec sh -c "..." command line. When the file is large enough (e.g. an accumulated session history .jsonl), the resulting command line exceeds the OS single-argument / command-line length limit and the process fails to start:
- Windows:
java.io.IOException: CreateProcess error=206, The filename or extension is too long (command line limit ~32 KB).
- Linux: same root cause, fails with
E2BIG once a single arg exceeds MAX_ARG_STRLEN (~128 KB). Higher threshold, so much rarer, but not immune.
This breaks the asynchronous session-log mirroring (SessionTree.scheduleMirror → mirrorToFilesystem → uploadFiles) during normal conversations once the session log grows.
Affected version
agentscope-harness:1.1.0-SNAPSHOT
Root cause (source)
io.agentscope.harness.agent.filesystem.sandbox.SandboxBackedFilesystem#uploadFiles:
String base64Content = Base64.getEncoder().encodeToString(content); // full file content
String escapedPath = shellSingleQuote(path);
String cmd =
"mkdir -p $(dirname " + escapedPath + ") && "
+ "printf '%s' '" + base64Content + "' | base64 -d > " + escapedPath;
ExecResult result = active.exec(runtimeContext, cmd, null);
This cmd (containing the entire base64 blob, which is ~1.33x the original size) is then passed to io.agentscope.harness.agent.sandbox.impl.docker.DockerSandbox#doExec, which puts it verbatim as the last argument:
List<String> cmd = new ArrayList<>();
cmd.add("docker"); cmd.add("exec");
cmd.add("-w"); cmd.add(workspaceRoot);
cmd.add(containerId);
cmd.add("sh"); cmd.add("-c");
cmd.add(command); // <-- entire base64 blob ends up on the command line
ProcessBuilder pb = new ProcessBuilder(cmd);
Process process = pb.start(); // throws CreateProcess error=206 on Windows / E2BIG on Linux
So the maximum file size is bounded by the OS command-line length limit, not by the sandbox.
Stack trace (Windows)
[sandbox-fs] uploadFiles failed for path: agents/<Agent>/sessions/main-<uuid>.jsonl
java.io.IOException: Cannot run program "docker": CreateProcess error=206, The filename or extension is too long.
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1143)
at io.agentscope.harness.agent.sandbox.impl.docker.DockerSandbox.doExec(DockerSandbox.java:152)
at io.agentscope.harness.agent.sandbox.AbstractBaseSandbox.exec(AbstractBaseSandbox.java:176)
at io.agentscope.harness.agent.filesystem.sandbox.SandboxBackedFilesystem.uploadFiles(SandboxBackedFilesystem.java:113)
at io.agentscope.harness.agent.memory.session.SessionTree.mirrorToFilesystem(SessionTree.java:585)
at io.agentscope.harness.agent.memory.session.SessionTree.lambda$scheduleMirror$4(SessionTree.java:466)
Caused by: java.io.IOException: CreateProcess error=206, The filename or extension is too long.
Steps to reproduce
- Build a
HarnessAgent with the Docker sandbox filesystem (IsolationScope.USER) on a Windows host with Docker Desktop.
- Hold a multi-turn conversation so the agent's session history (
sessions/main-*.jsonl) grows beyond ~32 KB.
- On the next session mirror,
uploadFiles builds a docker exec sh -c "...base64..." command line that exceeds the Windows limit → CreateProcess error=206.
(On Linux the same happens once a single mirrored file exceeds ~96 KB raw / ~128 KB base64.)
Impact
- Conversation and in-container tool execution still work; only the asynchronous session-log mirroring to the container fails repeatedly, producing noisy WARN logs.
- On Windows it triggers very quickly (low ~32 KB limit), effectively making the Docker sandbox filesystem unusable for normal-length conversations there.
Suggested fix
Avoid putting file bytes on the command line. The same class already does this correctly for workspace transfer in DockerSandbox#doHydrateWorkspace, which pipes a tar archive through docker exec -i ... tar -xf - via stdin:
ProcessBuilder pb = new ProcessBuilder("docker","exec","-i",containerId,"tar","-xf","-","-C",dir);
// archive bytes are written to process stdin, NOT the command line
uploadFiles should use the same stdin-pipe approach (e.g. docker exec -i <c> sh -c 'cat > <path>', or tar via stdin), so file size is bounded by stream throughput rather than the OS command-line limit. This makes it platform-independent and removes the Windows ~32 KB ceiling.
Environment
- OS: Windows (also affects Linux for large files)
- Java: 17
- Docker: Docker Desktop
- agentscope-harness: 1.1.0-SNAPSHOT
Summary
SandboxBackedFilesystem.uploadFiles(...)mirrors files into the Docker sandbox by base64-encoding the whole file content and embedding it as a single argument of adocker exec sh -c "..."command line. When the file is large enough (e.g. an accumulated session history.jsonl), the resulting command line exceeds the OS single-argument / command-line length limit and the process fails to start:java.io.IOException: CreateProcess error=206, The filename or extension is too long(command line limit ~32 KB).E2BIGonce a single arg exceedsMAX_ARG_STRLEN(~128 KB). Higher threshold, so much rarer, but not immune.This breaks the asynchronous session-log mirroring (
SessionTree.scheduleMirror→mirrorToFilesystem→uploadFiles) during normal conversations once the session log grows.Affected version
agentscope-harness:1.1.0-SNAPSHOTRoot cause (source)
io.agentscope.harness.agent.filesystem.sandbox.SandboxBackedFilesystem#uploadFiles:This
cmd(containing the entire base64 blob, which is ~1.33x the original size) is then passed toio.agentscope.harness.agent.sandbox.impl.docker.DockerSandbox#doExec, which puts it verbatim as the last argument:So the maximum file size is bounded by the OS command-line length limit, not by the sandbox.
Stack trace (Windows)
Steps to reproduce
HarnessAgentwith the Docker sandbox filesystem (IsolationScope.USER) on a Windows host with Docker Desktop.sessions/main-*.jsonl) grows beyond ~32 KB.uploadFilesbuilds adocker exec sh -c "...base64..."command line that exceeds the Windows limit →CreateProcess error=206.(On Linux the same happens once a single mirrored file exceeds ~96 KB raw / ~128 KB base64.)
Impact
Suggested fix
Avoid putting file bytes on the command line. The same class already does this correctly for workspace transfer in
DockerSandbox#doHydrateWorkspace, which pipes a tar archive throughdocker exec -i ... tar -xf -via stdin:uploadFilesshould use the same stdin-pipe approach (e.g.docker exec -i <c> sh -c 'cat > <path>', or tar via stdin), so file size is bounded by stream throughput rather than the OS command-line limit. This makes it platform-independent and removes the Windows ~32 KB ceiling.Environment