vxcontrol/pentagi · critical

failed to create resources directory: %w

Error message

failed to create resources directory: %w

What it means

EnsureResourcesDir creates the resources blob-storage directory (<dataDir>/resources, mode 0755) via os.MkdirAll and wraps any OS error with this message. Callers (CommitBlob, promoteToResources, UploadResources) invoke it before writing blob files, so failure here means the storage root cannot be prepared and the resource write must abort.

Source

Thrown at backend/pkg/resources/resources.go:66

// ResourcesDir returns the absolute path to the flat blob storage directory.
func ResourcesDir(dataDir string) string {
	return filepath.Join(dataDir, ResourcesDirName)
}

// BlobPath returns the absolute path to the .blob file for a given MD5 hash.
func BlobPath(dataDir, hash string) string {
	cleanHash := strings.ToLower(strings.TrimSpace(hash))
	if !IsValidBlobHash(cleanHash) {
		return filepath.Join(ResourcesDir(dataDir), invalidBlobHashFileName)
	}
	return filepath.Join(ResourcesDir(dataDir), cleanHash+".blob")
}

// EnsureResourcesDir creates the resources storage directory if it does not exist.
func EnsureResourcesDir(dataDir string) error {
	if err := os.MkdirAll(ResourcesDir(dataDir), 0755); err != nil {
		return fmt.Errorf("failed to create resources directory: %w", err)
	}
	return nil
}

// ComputeFileMD5 reads r to EOF and returns the lowercase hex MD5 digest.
func ComputeFileMD5(r io.Reader) (string, error) {
	h := md5.New()
	if _, err := io.Copy(h, r); err != nil {
		return "", fmt.Errorf("failed to compute MD5: %w", err)
	}
	return hex.EncodeToString(h.Sum(nil)), nil
}

// IsValidBlobHash reports whether hash is a hex-encoded MD5 digest.
func IsValidBlobHash(hash string) bool {
	if len(hash) != md5.Size*2 {
		return false
	}

View on GitHub (pinned to ea665308ba)

Solutions

  1. Check the wrapped %w cause and errno to identify the OS-level reason.
  2. Verify the configured data dir (DATA_DIR / config value) points to a writable directory, not a file: ls -ld <dataDir> and check it is a directory.
  3. Fix permissions/ownership: chown or chmod the data directory (or its parent) for the user running the process.
  4. If running in Docker, ensure the data volume is not mounted read-only (remove :ro from docker-compose).
  5. Free disk space / check mount health (df -h, dmesg) if the errno is ENOSPC or EIO.

Example fix

// before: data dir is a file, so MkdirAll fails with ENOTDIR
$ touch /var/lib/pentagi/data
DATA_DIR=/var/lib/pentagi/data
// after: data dir is a real, writable directory
$ rm /var/lib/pentagi/data && mkdir -p /var/lib/pentagi/data && chown pentagi:pentagi /var/lib/pentagi/data
DATA_DIR=/var/lib/pentagi/data
Defensive patterns

Strategy: try-catch

Validate before calling

// check writability before attempting blob writes
dir := resources.ResourcesDir(dataDir)
if fi, err := os.Stat(dir); err == nil && !fi.IsDir() {
    return fmt.Errorf("data dir path %s exists but is not a directory", dir)
}
if err := resources.EnsureResourcesDir(dataDir); err != nil {
    return fmt.Errorf("storage not writable: %w", err)
}

Type guard

func resourcesDirReady(dataDir string) bool {
    fi, err := os.Stat(resources.ResourcesDir(dataDir))
    return err == nil && fi.IsDir()
}

Try / catch

if err := resources.EnsureResourcesDir(cfg.DataDir); err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrPermission) {
        log.Fatalf("cannot create resources dir %s: permission denied — fix DATA_DIR ownership/mount", cfg.DataDir)
    }
    return fmt.Errorf("failed to create resources directory: %w", err)
}

Prevention

When it happens

Trigger: os.MkdirAll(ResourcesDir(dataDir), 0755) returns a non-nil error at resources.go:65 — the path's parent exists but is a file (ENOTDIR), a permissions problem (EACCES/EACCES on mkdir), a read-only filesystem (EROFS), or disk/device errors. dataDir comes from configuration.

Common situations: DATA_DIR env var misconfigured to a path that is a regular file or does not exist with unwritable parents; running the container/binary as a non-root user against a root-owned data directory; read-only container volume mount on the data dir; disk full or I/O errors on the host.

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/3c3e3db2b403ec8a. Report an issue: GitHub.