vxcontrol/pentagi · warning
%w: cannot move directory into itself
Error message
%w: cannot move directory into itself
What it means
moveDirResource rejects a move where the destination path lies inside the source directory (PathHasPrefix), which would create a cycle and corrupt the tree. It wraps errResourceInvalid so callers can classify it as caller error rather than a server failure. No changes are made.
Source
Thrown at backend/pkg/server/services/resources.go:935
}
updated, err := updateMovedResource(tx, src, targetPath, time.Now())
if err != nil {
return result, err
}
result.Updated = append(result.Updated, convertResource(updated))
return result, nil
}
func (s *ResourceService) moveDirResource(
tx *gorm.DB,
uid uint64,
srcPath, dstPath string,
force bool,
) (moveResourceResult, error) {
result := moveResourceResult{}
if resources.PathHasPrefix(dstPath, srcPath) {
return result, fmt.Errorf("%w: cannot move directory into itself", errResourceInvalid)
}
// Moving a directory to root (dstPath=="") means placing it at root level
if dstPath == "" {
dstPath = path.Base(srcPath)
}
createdParents, deletedParents, orphanHashes, err := ensureResourceDirs(tx, uid, resources.ParentDir(dstPath), force)
if err != nil {
return result, err
}
result.Added = append(result.Added, convertResources(createdParents)...)
result.DeletedBefore = append(result.DeletedBefore, convertResources(deletedParents)...)
result.OrphanHashes = append(result.OrphanHashes, orphanHashes...)
dest, destExists, err := findResourceByPath(tx, uid, dstPath)
if err != nil {
return result, err
}View on GitHub (pinned to ea665308ba)
Solutions
- Validate that dstPath does not start with srcPath + "/" before calling
- Match errors.Is(err, errResourceInvalid) and reject the operation in the UI
- Normalize both paths (clean trailing slashes) before comparison to avoid false negatives
Example fix
// before
svc.MoveResource(ctx, uid, []Source{{Path: "/a"}}, "/a/sub", false)
// after
if resources.PathHasPrefix("/a/sub", "/a") {
return fmt.Errorf("cannot move %q into itself", "/a")
}
svc.MoveResource(ctx, uid, []Source{{Path: "/a"}}, "/a/sub", false) Defensive patterns
Strategy: validation
Validate before calling
if resources.PathHasPrefix(dstPath, srcPath) {
return fmt.Errorf("refusing move: %q into %q", srcPath, dstPath)
} Try / catch
err := svc.MoveResource(ctx, uid, []Source{{Path: srcPath}}, dstPath, false)
if errors.Is(err, services.ErrResourceInvalid) {
// reject in UI: cannot move folder into itself
} Prevention
- Check path prefixes in any recursive move logic
- Disable drop targets that are descendants of the dragged folder
- Clean/normalize paths before validation
When it happens
Trigger: Calling MoveResource with dstPath='/a/b' and srcPath='/a' (or dstPath equal to srcPath), e.g. moving directory /a into /a/sub.
Common situations: Recursive filesystem walks that try to move a parent into its own child; UI allowing a folder to be dropped into one of its descendants; scripts building destination paths by string concatenation without prefix checks.
Related errors
- %w: source and destination are the same for %q
- %w: destination %q is a file; cannot move multiple sources i
- %w: cannot copy directory %q into itself
- unsupported subtask status: %s
- reading uploads cache: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/a41285dd5129931a.
Report an issue: GitHub.