vxcontrol/pentagi · error

failed to create parent directory for '%s': %w

Error message

failed to create parent directory for '%s': %w

What it means

Before writing each regular file, ExtractTar creates its parent directory with os.MkdirAll(filepath.Dir(entryPath), 0755). This error wraps that failure. entryPath has passed cleaning and containment checks, so causes are environmental: filesystem permissions, conflicts, or space.

Source

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

		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)
			}
			filesCount++
			if filesCount > MaxPullFiles {
				return fmt.Errorf("tar archive exceeds maximum file count of %d", MaxPullFiles)
			}
			totalSize += hdr.Size
			if totalSize > MaxPullTotalSize {
				return fmt.Errorf("tar archive exceeds maximum total size of %d bytes", MaxPullTotalSize)
			}

			if err := os.MkdirAll(filepath.Dir(entryPath), 0755); err != nil {
				return fmt.Errorf("failed to create parent directory for '%s': %w", entryPath, err)
			}

			f, err := os.OpenFile(entryPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
			if err != nil {
				return fmt.Errorf("failed to create file '%s': %w", entryPath, err)
			}
			_, copyErr := io.CopyN(f, tr, hdr.Size)
			f.Close()
			if copyErr != nil {
				return fmt.Errorf("failed to write file '%s': %w", entryPath, copyErr)
			}
		}
	}

	return nil
}

func ZipDirectory(w io.Writer, dirPath string) (err error) {

View on GitHub (pinned to ea665308ba)

Solutions

  1. Clear the destination directory before re-extracting so stale files don't shadow directory paths.
  2. Check the wrapped errno: ENOSPC → free disk; EACCES → fix volume ownership/permissions; ENAMETOOLONG → flatten archive paths on the producer side.
  3. Ensure destDir exists and is writable by the process user before calling ExtractTar.
  4. Avoid extremely deep directory nesting when building the archive.

Example fix

// before
err := flowfiles.ExtractTar(rc, destDir)
// after
os.RemoveAll(destDir) // fresh extraction target
if err := os.MkdirAll(destDir, 0o755); err != nil { return err }
err := flowfiles.ExtractTar(rc, destDir)
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(destDir)
if err != nil || !info.IsDir() {
    return fmt.Errorf("destDir must exist as a writable directory")
}
probe, err := os.MkdirTemp(destDir, ".wprobe-*")
if err != nil {
    return fmt.Errorf("destDir not writable: %w", err)
}
os.Remove(probe)

Try / catch

err := flowfiles.ExtractTar(rc, destDir)
if err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) {
        switch {
        case errors.Is(pe.Err, syscall.ENOSPC):
            return fmt.Errorf("destination disk full: %w", err)
        case errors.Is(pe.Err, syscall.EACCES), errors.Is(pe.Err, syscall.EROFS):
            return fmt.Errorf("destination volume not writable: %w", err)
        case errors.Is(pe.Err, syscall.ENAMETOOLONG):
            return fmt.Errorf("archive paths too long for target fs: %w", err)
        }
    }
    return err
}

Prevention

When it happens

Trigger: os.MkdirAll fails for a nested entry's parent while extracting via PullFlowFiles: destDir read-only, a regular file already occupies a parent-path component (ENOTDIR), path too long (ENAMETOOLONG), or disk full.

Common situations: Deeply nested archives exceeding filesystem path limits; re-extraction over a previous partial extraction where files collide with directory paths; container volumes owned by a different UID.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


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