passbolt/passbolt_api · error · App\Error\Exception\CustomValidationException

Could not validate move data.

Error message

Could not validate move data.

What it means

This CustomValidationException is thrown when the move-operation data fails validation. FoldersRelationsMoveItemInUserTreeService aggregates errors from its assertion methods (folder parent validity, permission to move out of / into a folder, cycle detection) and, if any errors accumulated, handleValidationErrors raises this exception carrying the per-field error array. It protects the personal-folder-tree invariants before any persistence happens.

Solutions

  1. Inspect the 'errors' payload of the exception response — it tells which assertion failed (folder_parent_id, permission, or cycle).
  2. Verify the folder_parent_id exists and is a folder id, not a resource id, and was not deleted (check GET /folders).
  3. Confirm the authenticated user has the required permission (UPDATE/OWNER) on both the source and destination folders.
  4. Ensure the move does not place a folder inside its own descendant tree; re-parent the destination folder first if needed.
  5. Fix client validation to check cycle and permission rules before issuing the move request.

Example fix

// before: move without checks
await moveFolder(folderId, { folder_parent_id: parentId });

// after: validate first
if (await isDescendant(parentId, folderId)) {
  throw new Error('Cannot move a folder into its own descendant');
}
await moveFolder(folderId, { folder_parent_id: parentId });
Defensive patterns

Strategy: validation

Validate before calling

const parentExists = folders.some(f => f.id === moveData.folder_parent_id);
const createsCycle = await isDescendant(moveData.folder_parent_id, folderId);
if (!parentExists || createsCycle) throw new Error('Invalid move: bad parent or cycle');

Try / catch

try { await moveFolder(id, data); } catch (e) { if (e.response?.status === 400 && e.response?.data?.errors) handleFieldErrors(e.response.data.errors); else throw e; }

Prevention

When it happens

Trigger: Calling the folders move endpoint (PUT /folders/<id>/move or resource move) where: the folder_parent_id points to a non-existent or invalid folder; the user lacks permission on the source folder to move content out; the user lacks permission on the destination folder to move content in; or the move would create a cycle in the folder hierarchy (moving a folder into one of its own descendants).

Common situations: Front-end passes a stale folder_parent_id after a folder was deleted by another user; a user with read-only access on a parent folder tries to move items; automation/scripts try to move a folder into its own subtree; passing an id belonging to a resource where a folder id is expected (or vice versa).

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/8a31aa5882dd6882. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltCe/Folders/src/Service/FoldersRelations/FoldersRelationsMoveItemInUserTreeService.php:140

        $exists = $this->foldersRelationsTable->isItemInUserTree($uac->getId(), $folderParentId);
        if (!$exists) {
            $errors = ['folder_parent_id' => ['folder_exists' => 'The folder parent does not exist.']];
            $this->handleValidationErrors($errors);
        }
    }

    /**
     * Handle move validation errors.
     *
     * @param array|null $errors The list of errors
     * @return void
     * @throws \App\Error\Exception\CustomValidationException If the provided data does not validate.
     */
    private function handleValidationErrors(?array $errors = []): void
    {
        if (!empty($errors)) {
            $msg = __('Could not validate move data.');
            throw new CustomValidationException($msg, $errors, $this->foldersRelationsTable);
        }
    }

    /**
     * Check if the user can move content out of the folder.
     * - User can always move content from root.
     * - User can always move content out of a personal folder.
     * - User can move content out of a shared folder if the user has at least an update permission on the folder to
     *   move and the original parent folder.
     *
     * @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
     * @param string $foreignModel The entity model
     * @param string $foreignId The entity id
     * @param string|null $originalFolderParentId The original folder location. Null if root
     * @return void
     */
    private function assertUserCanMoveOutOfFolder(
        UserAccessControl $uac,

View on GitHub (pinned to 31c1bbc10f)