vxcontrol/pentagi · error

failed to read tar entry: %w

Error message

failed to read tar entry: %w

What it means

ExtractTar iterates a tar archive with tar.Reader.Next; this error wraps any tar-stream error that is not clean EOF — corrupted archive bytes, truncated stream, unsupported format, or an underlying read failure from the source reader. It fires before any entry-specific handling, so extraction aborts with whatever was already written left in destDir.

Source

Thrown at backend/pkg/flowfiles/files.go:385

	return ""
}

func WriteUploadsTar(w *io.PipeWriter, uploadDir string) error {
	return writeDirectoryTar(w, uploadDir, UploadsDirName, "upload", "uploads")
}

func ExtractTar(r io.Reader, destDir string) error {
	tr := tar.NewReader(r)
	var filesCount int
	var totalSize int64
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return fmt.Errorf("failed to read tar entry: %w", err)
		}
		if hdr.Typeflag == tar.TypeSymlink || hdr.Typeflag == tar.TypeLink {
			continue
		}

		entryPath := filepath.Join(destDir, filepath.Clean(filepath.FromSlash(hdr.Name)))
		if !IsWithinDir(entryPath, destDir) {
			continue
		}

		switch hdr.Typeflag {
		case tar.TypeDir:
			if err := os.MkdirAll(entryPath, 0755); err != nil {
				return fmt.Errorf("failed to create directory '%s': %w", entryPath, err)
			}
		case tar.TypeReg, tar.TypeRegA:
			if hdr.Size < 0 {
				return fmt.Errorf("tar entry '%s' has invalid size %d", hdr.Name, hdr.Size)

View on GitHub (pinned to ea665308ba)

Solutions

  1. Verify the archive is uncompressed tar — if the producer gzips, wrap the reader with gzip.NewReader(r) before ExtractTar.
  2. Test the exact bytes with `tar -tvf archive.tar` locally to confirm corruption vs consumer bug.
  3. Check the transfer path for truncation (proxy limits, closed pipes); ensure the writer closes the pipe/stream before extraction.
  4. Regenerate the archive from the source with archive/tar or GNU tar defaults.

Example fix

// before
err := flowfiles.ExtractTar(resp.Body, destDir)
// after
var r io.Reader = resp.Body
if strings.Contains(resp.Header.Get("Content-Type"), "gzip") {
    r, err = gzip.NewReader(resp.Body)
    if err != nil { return err }
}
err = flowfiles.ExtractTar(r, destDir)
Defensive patterns

Strategy: validation

Validate before calling

// Verify the payload is uncompressed tar before extraction:
br := make([]byte, 262)
n, _ := io.ReadFull(rc, br)
if n < 262 {
    return fmt.Errorf("stream too short to be a tar archive")
}
if !bytes.Equal(br[257:262], []byte("ustar")) {
    // maybe gzipped — decompress first
    gz, err := gzip.NewReader(io.MultiReader(bytes.NewReader(br[:n]), rc))
    if err != nil {
        return fmt.Errorf("not tar or gzip: %w", err)
    }
    rc = gz
} else {
    rc = io.MultiReader(bytes.NewReader(br[:n]), rc)
}

Try / catch

err := flowfiles.ExtractTar(rc, destDir)
if err != nil {
    if strings.Contains(err.Error(), "failed to read tar entry") {
        return fmt.Errorf("archive is corrupt, truncated, or not plain tar: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: PullFlowFiles receives an archive whose bytes are not valid tar: the producer wrote gzip but the consumer expects raw tar, the stream was truncated mid-transfer, the HTTP body was cut off, or the source pipe errored.

Common situations: Sender gzipped the tarball (gzip data read as tar gives 'tar: invalid tar header'); interrupted container-to-container copy; wrong Content-Encoding stripping; older/newer tar format incompatibilities (pax/gnu headers).

Related errors


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