{"record":{"id":"7d5ce4e077e3f8c3","repo":"vxcontrol/pentagi","slug":"failed-to-create-file-s-w","errorCode":null,"errorMessage":"failed to create file '%s': %w","messagePattern":"failed to create file '(.+?)': %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/flowfiles/files.go","lineNumber":420,"sourceCode":"\t\t\tif hdr.Size < 0 {\n\t\t\t\treturn fmt.Errorf(\"tar entry '%s' has invalid size %d\", hdr.Name, hdr.Size)\n\t\t\t}\n\t\t\tfilesCount++\n\t\t\tif filesCount > MaxPullFiles {\n\t\t\t\treturn fmt.Errorf(\"tar archive exceeds maximum file count of %d\", MaxPullFiles)\n\t\t\t}\n\t\t\ttotalSize += hdr.Size\n\t\t\tif totalSize > MaxPullTotalSize {\n\t\t\t\treturn fmt.Errorf(\"tar archive exceeds maximum total size of %d bytes\", MaxPullTotalSize)\n\t\t\t}\n\n\t\t\tif err := os.MkdirAll(filepath.Dir(entryPath), 0755); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create parent directory for '%s': %w\", entryPath, err)\n\t\t\t}\n\n\t\t\tf, err := os.OpenFile(entryPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create file '%s': %w\", entryPath, err)\n\t\t\t}\n\t\t\t_, copyErr := io.CopyN(f, tr, hdr.Size)\n\t\t\tf.Close()\n\t\t\tif copyErr != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to write file '%s': %w\", entryPath, copyErr)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc ZipDirectory(w io.Writer, dirPath string) (err error) {\n\tzw := zip.NewWriter(w)\n\tdefer func() {\n\t\tif cerr := zw.Close(); err == nil {\n\t\t\terr = cerr\n\t\t}","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/flowfiles/files.go#L402-L438","documentation":"ExtractTar opens each regular-file entry with os.OpenFile(entryPath, O_CREATE|O_WRONLY|O_TRUNC, 0644) after its parent directory exists; failure here aborts with this error. Because the path was already sanitized and parents created, causes are filesystem-level: permissions, read-only volume, name conflicts, or resource exhaustion (too many open files).","triggerScenarios":"os.OpenFile fails during PullFlowFiles extraction: destDir volume is read-only or lacks write permission, a directory already exists at entryPath (EISDIR), filename contains characters invalid for the host FS, EMFILE/ENFILE fd exhaustion, or disk full at open/truncate time.","commonSituations":"Archives built on case-sensitive/other-OS filesystems with characters like ':' or '\\\\' extracted onto stricter filesystems; service running as unprivileged UID against a root-owned volume; fd leaks elsewhere in the process hitting the ulimit.","solutions":["Read the wrapped errno: EACCES/EROFS → fix volume permissions or mount rw; EISDIR → clear the conflicting directory from a prior extraction; EMFILE → raise ulimit -n or fix fd leaks.","Sanitize/flatten entry names when producing the tar to avoid characters invalid on the target OS.","Ensure the process user owns destDir (chown -R service:service destDir).","Check disk space (ENOSPC) on the destination volume."],"exampleFix":"// before\nerr := flowfiles.ExtractTar(rc, destDir)\n// after\n// run as the volume owner or pre-chown the dir:\n// $ chown -R 10001:10001 /var/lib/pentagi/uploads\nif err := os.MkdirAll(destDir, 0o755); err != nil { return err }\nerr := flowfiles.ExtractTar(rc, destDir)","handlingStrategy":"try-catch","validationCode":"// Ensure destDir is writable and the process is under fd limits:\ninfo, err := os.Stat(destDir)\nif err != nil || !info.IsDir() {\n    return fmt.Errorf(\"destDir missing or not a directory\")\n}\nif err := unix.Access(destDir, unix.W_OK); err != nil {\n    return fmt.Errorf(\"destDir not writable by current user: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := flowfiles.ExtractTar(rc, destDir)\nif err != nil {\n    var pe *fs.PathError\n    if errors.As(err, &pe) {\n        switch {\n        case errors.Is(pe.Err, syscall.EACCES), errors.Is(pe.Err, syscall.EROFS):\n            return fmt.Errorf(\"cannot write into %s (check ownership/mount): %w\", destDir, err)\n        case errors.Is(pe.Err, syscall.EMFILE), errors.Is(pe.Err, syscall.ENFILE):\n            return fmt.Errorf(\"fd limit exhausted: %w\", err)\n        case errors.Is(pe.Err, syscall.EISDIR):\n            return fmt.Errorf(\"stale directory blocks a file entry; clean destDir: %w\", err)\n        case errors.Is(pe.Err, syscall.ENOSPC):\n            return fmt.Errorf(\"disk full: %w\", err)\n        }\n    }\n    return err\n}","preventionTips":["Run the service as the owner of the destination volume, or chown the uploads dir at startup.","Mount destination volumes read-write; avoid read-only rootfs for extraction targets.","Watch open-file-descriptor usage (lsof | wc -l vs ulimit -n) on busy instances.","Sanitize archive entry names at production time to characters valid on the target OS.","Extract to a fresh temp dir per request and swap into place atomically."],"tags":["filesystem","tar","extract","openfile","permissions"],"backgroundTag":"file-open-permission-denied","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}