vxcontrol/pentagi · error
failed to delete file blocking directory %q: %w
Error message
failed to delete file blocking directory %q: %w
What it means
ensureResourceDirs walks each path segment of a target resource directory and, when a segment exists in the DB as a FILE (not a dir) and the caller passed force=true, it deletes the blocking row first. This error wraps the underlying GORM/PostgreSQL failure of that forced delete (tx.Delete), e.g. FK constraint, connection loss, or serialization failure inside the transaction.
Source
Thrown at backend/pkg/server/services/resources.go:2102
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,
Size: 0,
IsDir: true,
}View on GitHub (pinned to ea665308ba)
Solutions
- Inspect the wrapped %w cause: if it is a foreign-key violation, remove or reassign rows referencing the resource (e.g. logs/attachments) before forcing the delete.
- Retry the operation — transient DB/connection errors resolve on retry within a fresh transaction.
- Verify DB connectivity and migration state (goose migrations applied) if the error is a missing table/column.
- If the force-delete semantics are unwanted, retry the call with force=false to get the clean errResourceConflict instead.
Example fix
// before
created, deleted, orphans, err := svc.UploadResources(ctx, uid, dirPath, files, true) // force=true collides with file 'reports'
// after
existing, _ := svc.FindResourceByPath(uid, "reports")
if existing != nil && !existing.IsDir {
// clean blocking file references first, then upload
svc.DeleteResourceReferences(uid, "reports")
}
created, deleted, orphans, err := svc.UploadResources(ctx, uid, dirPath, files, true) Defensive patterns
Strategy: try-catch
Validate before calling
res, ok, _ := svc.FindResourceByPath(uid, dirPath)
if ok && !res.IsDir && !forceAllowed {
return fmt.Errorf("path %q is an existing file; refusing dir upload", dirPath)
} Type guard
func isFKViolation(err error) bool {
var pgErr *pgconn.PgError
return errors.As(err, &pgErr) && pgErr.Code == "23503"
} Try / catch
created, deleted, orphans, err := ensureResourceDirs(tx, uid, dirPath, force)
if err != nil && strings.Contains(err.Error(), "failed to delete file blocking directory") {
// inspect wrapped cause with errors.Unwrap / errors.As(*pgconn.PgError)
// decide: retry, clean referencing rows, or surface conflict to caller
} Prevention
- Check for path collisions with findResourceByPath before force-uploading a directory tree.
- Clean up rows referencing the resource (logs, attachments) before forcing deletion.
- Retry transient DB errors with backoff inside a fresh transaction.
- Keep goose migrations current so FK definitions match expectations.
When it happens
Trigger: Calling promoteToResources, UploadResources, moveMultipleSources, moveFileResource, moveDirResource, or copyMultipleSources with a dirPath whose intermediate segment collides with an existing file resource and force=true, and the DELETE statement fails (DB error: FK violation on referenced rows, dead connection, tx already aborted).
Common situations: User uploads a folder whose name matches an existing uploaded file while enabling 'overwrite/force'; the row being deleted is referenced by other tables (task logs, search logs) so Postgres rejects the delete; transient DB outage mid-transaction.
Related errors
- failed to fetch resources: %w
- failed to copy resource: %w
- failed to list resources: %w
- failed to create resource directory %q: %w
- failed to delete subtasks for task %d: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/1a05ddc704c8160c.
Report an issue: GitHub.