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

  1. 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.
  2. Retry the operation — transient DB/connection errors resolve on retry within a fresh transaction.
  3. Verify DB connectivity and migration state (goose migrations applied) if the error is a missing table/column.
  4. 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

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


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