vxcontrol/pentagi · warning
%w: resource %q already exists and is not a directory
Error message
%w: resource %q already exists and is not a directory
What it means
ensureResourceDirs builds every missing parent directory row for a target path. If an intermediate path component already exists as a FILE (IsDir=false), a directory cannot be created there: without force it returns errResourceConflict wrapped as 'already exists and is not a directory'; with force it deletes the blocking file instead.
Source
Thrown at backend/pkg/server/services/resources.go:2099
return nil, nil, nil, nil
}
parts := strings.Split(dirPath, "/")
created := make([]models.UserResource, 0, len(parts))
deleted := make([]models.UserResource, 0, len(parts))
orphanHashes := make([]string, 0, len(parts))
current := ""
for _, part := range parts {
current = resources.FilePath(current, part)
existing, exists, err := findResourceByPath(tx, uid, current)
if err != nil {
return nil, nil, nil, err
}
if exists {
if !existing.IsDir {
if !force {
return nil, nil, nil, fmt.Errorf("%w: resource %q already exists and is not a directory", errResourceConflict, current)
}
if err := tx.Delete(&existing).Error; err != nil {
return nil, nil, nil, fmt.Errorf("failed to delete file blocking directory %q: %w", current, err)
}
deleted = append(deleted, existing)
if existing.Hash != "" {
orphanHashes = append(orphanHashes, existing.Hash)
}
} else {
continue
}
}
rec := models.UserResource{
UserID: uid,
Hash: "",
Name: path.Base(current),
Path: current,View on GitHub (pinned to ea665308ba)
Solutions
- Delete or rename the existing file that occupies the directory path, or pass force=true to auto-delete it
- Pick a different target path that does not traverse an existing file
- List resources to find the offending file at one of the parent segments before uploading
Example fix
// before
upload("reports/2024/q1.csv") // 'reports' exists as a file → conflict
// after
upload("reports/2024/q1.csv?force=true") // deletes blocking file, or:
deleteResource("reports"); upload("reports/2024/q1.csv") Defensive patterns
Strategy: validation
Validate before calling
// check every parent segment before upload/move/copy
segs := strings.Split(strings.Trim(target, "/"), "/")
cur := ""
for _, s := range segs {
cur += "/" + s
if e, ok := lookup(uid, cur); ok && !e.IsDir {
return fmt.Errorf("%s is a file; delete it or use force", cur)
}
} Type guard
func pathClearForDir(entries []Resource, dir string) bool {
for _, e := range entries {
if (e.Path == dir || strings.HasPrefix(dir, e.Path+"/")) && !e.IsDir {
return false
}
}
return true
} Try / catch
if err := upload(target, r); err != nil {
if errors.Is(err, errResourceConflict) {
return fmt.Errorf("a file blocks a directory component of %s; delete it or retry with force", target)
}
return err
} Prevention
- Before uploading into new subfolders, confirm no parent segment exists as a file
- Avoid file names that could later be used as folder names in the same tree
- Use force=true only when deleting the blocking file is acceptable
- Normalize/validate path segments client-side (no empty or colliding segments)
When it happens
Trigger: Uploading/moving/copying to path a/b/c when a or a/b is registered as a file, e.g. after a previous upload named 'a' as a file; also hit when path segments collide with an uploaded file's name.
Common situations: Uploading a file named 'data' then later uploading to data/file.txt; directory layouts changed between API versions; scripts creating flat file names that later collide with folder paths.
Related errors
- Token.InvalidRequest
- resource %d not found
- %w: destination %q is a file; cannot move multiple sources i
- %w: cannot copy directory into itself
- Internal
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/2a370c7ef1ca7ce5.
Report an issue: GitHub.