agentscope-ai / agentscope-ai/agentscope-java

[harness][sandbox] SandboxBackedFilesystem.uploadFiles fails with CreateProcess error=206 / E2BIG because file content is base64-embedded into the docker exec command line

Aberta
#1,560 2 comentários 1 reação 0 responsáveis Ver no GitHub
area/harness bug
Linguagem predominante
Java
Estrelas
5.6k
Forks
1.3k
Merge médio
4d 12h
PRs com merge (30d)
77

Descrição

## 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`:

```java
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:

```java
List 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//sessions/main-.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

1. Build a `HarnessAgent` with the Docker sandbox filesystem (`IsolationScope.USER`) on a **Windows** host with Docker Desktop.
2. Hold a multi-turn conversation so the agent's session history (`sessions/main-*.jsonl`) grows beyond ~32 KB.
3. 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**:

```java
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 sh -c 'cat > '`, 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

Guia de contribuição

Abrir o guia de contribuição

Avaliação

Esta issue ainda não foi avaliada.

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.