vxcontrol/pentagi · error

failed to copy file: %w

Error message

failed to copy file: %w

What it means

Wraps any error returned by dockerClient.CopyFromContainer, which streams the file at `path` out of the container as a tar archive. The error originates in the Docker SDK / daemon layer — most often the path does not exist, the container is gone, or the daemon rejected the copy request — and is wrapped so the Docker cause is preserved via %w.

Source

Thrown at backend/pkg/tools/terminal.go:376

// readFileFromContainer copies path out of the flow's container and returns
// its content. It performs no terminal-log writes, so callers that need the
// content only as an intermediate step (e.g. EditFile, before reapplying a
// diff and writing back) don't echo a spurious "cat" transcript entry.
func (t *terminal) readFileFromContainer(ctx context.Context, flowID int64, path string) (string, error) {
	containerName := PrimaryTerminalName(t.tenantPrefix, flowID)

	isRunning, err := t.dockerClient.IsContainerRunning(ctx, t.containerLID)
	if err != nil {
		return "", fmt.Errorf("runtime verification failed: %w", err)
	}
	if !isRunning {
		return "", fmt.Errorf("container runtime is not operational")
	}

	reader, stats, err := t.dockerClient.CopyFromContainer(ctx, containerName, path)
	if err != nil {
		return "", fmt.Errorf("failed to copy file: %w", err)
	}
	defer reader.Close()

	var buffer strings.Builder
	tarReader := tar.NewReader(reader)
	for {
		tarHeader, err := tarReader.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return "", fmt.Errorf("failed to read tar header: %w", err)
		}

		if tarHeader.FileInfo().IsDir() {
			continue
		}

View on GitHub (pinned to ea665308ba)

Solutions

  1. Verify the path exists inside the container: `docker exec <container> ls -la <path>`; use an absolute path
  2. Confirm the container is running and the container name (PrimaryTerminalName(tenantPrefix, flowID)) still matches the actual container
  3. Inspect the wrapped %w cause (`errors.Unwrap` or the log output) — if it's 404 the path is wrong, if it's a daemon/transport error check `docker info`
  4. If the file lives on a mounted volume, check host-side mount permissions (uid/gid) inside the container
  5. Retry the operation if the cause is transient (daemon restart)

Example fix

// before
reader, stats, err := t.dockerClient.CopyFromContainer(ctx, containerName, path)
// after (caller-side)
var nfe *docker.NotFoundError // or errors.As on the wrapped cause
if err != nil && strings.Contains(err.Error(), "No such file") {
    return "", fmt.Errorf("file %q does not exist in container %s", path, containerName)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if path == "" || !filepath.IsAbs(path) {
    return fmt.Errorf("path must be a non-empty absolute path")
}
_, err := executor.Run(ctx, flowID, fmt.Sprintf("test -e %s && echo ok", path)) // existence probe

Try / catch

reader, stats, err := dockerClient.CopyFromContainer(ctx, name, path)
if err != nil {
    var nf objectNotFoundError
    if errors.As(err, &nf) {
        return fmt.Errorf("file %q not found in container %s", path, name)
    }
    return fmt.Errorf("failed to copy file: %w", err)
}

Prevention

When it happens

Trigger: ReadFile or EditFile called with a `path` that does not exist in the container, points outside an accessible scope, or when the Docker daemon cannot service CopyFromContainer (container removed mid-call, daemon restarting, permission denied on the path).

Common situations: Typo'd or wrong-container-relative path (path must be absolute inside the container); file deleted between listing and read; read-only volume mount rejecting access; container was recreated with a new name so the old name no longer resolves; Docker daemon socket permission issues.

Related errors


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