vxcontrol/pentagi · error

failed to read file-check output: %w

Error message

failed to read file-check output: %w

What it means

This error wraps a failure from io.ReadAll(resp.Reader) after successfully attaching to a Docker exec instance. The exec attach stream was opened but reading the combined stdout/stderr stream failed, typically because the connection was cut mid-read or the daemon closed it abnormally. resp.Close() is still called before returning, so no fd leak occurs.

Source

Thrown at backend/pkg/tools/tools.go:672

	containerName := PrimaryTerminalName(fte.cfg.TenantPrefix(), fte.flowID)
	createResp, err := fte.docker.ContainerExecCreate(ctx, containerName, client.ExecCreateOptions{
		Cmd:          cmd,
		AttachStdout: true,
		AttachStderr: true,
	})
	if err != nil {
		return nil, fmt.Errorf("failed to create file-check exec: %w", err)
	}

	resp, err := fte.docker.ContainerExecAttach(ctx, createResp.ID, client.ExecAttachOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to attach file-check exec: %w", err)
	}
	output, readErr := io.ReadAll(resp.Reader)
	resp.Close()
	if readErr != nil {
		return nil, fmt.Errorf("failed to read file-check output: %w", readErr)
	}
	inspect, err := fte.docker.ContainerExecInspect(ctx, createResp.ID)
	if err != nil {
		return nil, fmt.Errorf("failed to inspect file-check exec: %w", err)
	}
	if inspect.ExitCode != 0 {
		return nil, fmt.Errorf("file-check exec failed with exit code %d: %s", inspect.ExitCode, strings.TrimSpace(string(output)))
	}

	byContainerPath := make(map[string]fileSyncEntry, len(entries))
	for _, e := range entries {
		byContainerPath[e.containerPath] = e
	}

	var missing []fileSyncEntry
	for _, line := range strings.Split(string(output), "\n") {
		line = strings.TrimSpace(line)
		if line == "" {

View on GitHub (pinned to ea665308ba)

Solutions

  1. Check the wrapped readErr: 'unexpected EOF' or 'connection reset' indicates a dropped hijacked connection — verify daemon/network stability
  2. Confirm the sandbox container was not killed mid-run (docker inspect <container> --format '{{.State.OOMKilled}} {{.State.Status}}')
  3. Reduce output volume of the file-check command or stream/consume output incrementally with bounds instead of ReadAll
  4. Retry the whole file-check exec once on transient stream errors

Example fix

// before
output, readErr := io.ReadAll(resp.Reader)
resp.Close()
if readErr != nil {
	return nil, fmt.Errorf("failed to read file-check output: %w", readErr)
}
// after
output, readErr := io.ReadAll(io.LimitReader(resp.Reader, maxCheckOutputBytes))
resp.Close()
if readErr != nil {
	return nil, fmt.Errorf("failed to read file-check output: %w", readErr)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure the container and daemon connection are healthy before running the check
info, err := cli.ContainerInspect(ctx, containerID)
if err != nil || !info.State.Running {
	return fmt.Errorf("container not available for file-check: %v", err)
}

Try / catch

err := runFileCheck(ctx)
var transient bool
if err != nil && strings.Contains(err.Error(), "failed to read file-check output") {
	transient = true // hijacked stream dropped; safe to retry the whole exec once
}
if transient {
	err = runFileCheck(ctx)
}

Prevention

When it happens

Trigger: io.ReadAll(resp.Reader) returns an error: the hijacked connection to dockerd drops during command execution, the daemon restarts while the exec command is running, or the stream is aborted (e.g. container removed or OOM-killed mid-run).

Common situations: Long-running or high-output file-check commands inside a sandboxed container when the Docker daemon or network is unstable; container killed by resource limits while producing output; proxy/load balancer in front of remote DOCKER_HOST timing out the hijacked stream.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/d3dfb0381cb991ca. Report an issue: GitHub.