vxcontrol/pentagi · warning

%w: source and destination are the same for %q

Error message

%w: source and destination are the same for %q

What it means

This error is returned by moveMultipleSources when a requested source's resolved destination path (dstPath + source name) equals its current path, i.e. moving a resource onto itself. It wraps errResourceInvalid so callers can match the sentinel with errors.Is. The transaction is rolled back so no partial move is applied.

Source

Thrown at backend/pkg/server/services/resources.go:729

			return result, fmt.Errorf(
				"%w: sources %q and %q share the same base name %q",
				errResourceConflict, prev, src.Path, src.Name,
			)
		}
		basenameToSrc[src.Name] = src.Path
	}

	// Self-move guard: no source may be a directory that contains dstPath.
	for _, src := range srcs {
		if src.IsDir && resources.PathHasPrefix(dstPath, src.Path) {
			tx.Rollback()
			return result, fmt.Errorf(
				"%w: cannot move directory %q into itself", errResourceInvalid, src.Path,
			)
		}
		if resources.FilePath(dstPath, src.Name) == src.Path {
			tx.Rollback()
			return result, fmt.Errorf(
				"%w: source and destination are the same for %q", errResourceInvalid, src.Path,
			)
		}
	}

	// ── Ensure destination directory ──────────────────────────────────────────
	dest, destExists, err := findResourceByPath(tx, uid, dstPath)
	if err != nil {
		tx.Rollback()
		return result, err
	}
	if destExists && !dest.IsDir {
		tx.Rollback()
		return result, fmt.Errorf(
			"%w: destination %q is a file; cannot move multiple sources into it",
			errResourceConflict, dstPath,
		)
	}

View on GitHub (pinned to ea665308ba)

Solutions

  1. Check that FilePath(dstPath, src.Name) != src.Path for each source before calling MoveResource
  2. Filter out no-op entries from the source list client-side
  3. Match errors.Is(err, errResourceInvalid) and treat as success/no-op if the move is meant to be idempotent

Example fix

// before
res, err := svc.MoveResource(ctx, uid, sources, dstPath, false)
// after
filtered := slices.DeleteFunc(sources, func(s Source) bool {
    return resources.FilePath(dstPath, s.Name) == s.Path
})
res, err := svc.MoveResource(ctx, uid, filtered, dstPath, false)
Defensive patterns

Strategy: validation

Validate before calling

for _, s := range sources {
    if resources.FilePath(dstPath, s.Name) == s.Path {
        return fmt.Errorf("no-op move: %q", s.Path)
    }
}

Try / catch

if err := svc.MoveResource(ctx, uid, sources, dstPath, false); err != nil {
    if errors.Is(err, services.ErrResourceInvalid) {
        // treat as no-op / skip
    }
}

Prevention

When it happens

Trigger: Calling MoveResource with multiple sources where one source's target directory already contains (or resolves to) the same path, e.g. moving file 'a.txt' into directory '/' when it already lives at '/a.txt', or moving a dir into its own parent unchanged.

Common situations: Bulk drag-and-drop in a UI where a user drops a file onto the folder it already resides in; scripted bulk moves that compute destinations without checking current location; retries of an idempotent move after a prior success.

Related errors


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