Leantime/leantime · error · Leantime\Core\Exceptions\AuthorizationException

-32001

-32001

Error message

You are not allowed to re-sort one or more of these projects.

What it means

Projects::patchProjectStatusAndSorting() is the authorized JSON-RPC entry point for the project kanban status+sort update. It parses params shaped as {status => jQuery-serialized string like "item[]=3&item[]=7"} (ids extracted by stripping the 7-char prefix), and for every project id requires userCanManageProject(): role of manager or higher AND assignment to that project (admins/owners bypass). Any failing id throws AuthorizationException, mapped to JSON-RPC -32001, before any write happens.

Source

Thrown at app/Domain/Projects/Services/Projects.php:2745

     * @throws AuthorizationException If the caller cannot manage any project in the batch
     *
     * @api
     */
    public function patchProjectStatusAndSorting(array $params, ?string $handler = null): bool
    {
        foreach ($params as $status => $projectList) {
            if (! is_numeric($status) || empty($projectList)) {
                continue;
            }

            foreach (explode('&', $projectList) as $projectString) {
                // jQuery sortable serializes ids as "item[]=ID" (strip the 7-char prefix).
                $projectId = (int) substr($projectString, 7);
                if ($projectId <= 0) {
                    continue;
                }
                if (! $this->userCanManageProject($projectId)) {
                    throw new AuthorizationException('You are not allowed to re-sort one or more of these projects.');
                }
            }
        }

        return $this->updateProjectStatusAndSorting($params, $handler);
    }

    /**
     * Authorized JSON-RPC entry point for Program Timeline (Gantt) re-sorting.
     *
     * Validates manager+ access for every entity in the mixed payload (pgm-/ticket-
     * prefixed and legacy numeric ids) before delegating to updateProjectSorting().
     * Ticket ids are resolved to their project so the same manage-access rule applies.
     *
     * @param  array  $params  Map of (pgm-{id}|ticket-{id}|{id}) => sort position
     * @return bool True on success (false only if the underlying write fails)
     *
     * @throws NotFoundException If a ticket-{id} key references a ticket that does not exist

View on GitHub (pinned to 9a9f49f100)

Solutions

  1. Ensure the acting user has manager+ role and is assigned to every project in the batch (admin/owner bypasses the assignment check)
  2. Hide drag-drop sorting UI for non-managers so the invalid call is never made
  3. Catch AuthorizationException (-32001), then verify assignments with Projects::isUserAssignedToProject and retry with only the projects the user can manage

Example fix

// before
$result = $projectsService->patchProjectStatusAndSorting($params);

// after
foreach ($params as $status => $list) {
    foreach (explode('&', $list) as $item) {
        $pid = (int) substr($item, 7);
        if ($pid > 0 && ! $projectsService->userCanManageProject($pid)) {
            unset($params[$status]); // or abort with a clear message
            continue 2;
        }
    }
}
$result = $projectsService->patchProjectStatusAndSorting($params);
Defensive patterns

Strategy: validation

Validate before calling

foreach ($params as $status => $list) {
    foreach (explode('&', (string) $list) as $item) {
        $pid = (int) substr($item, 7);
        if ($pid > 0 && ! $projectsService->userCanManageProject($pid)) {
            return ['error' => "No manage rights on project {$pid}"]; // fail before the call
        }
    }
}

Try / catch

try {
    $ok = $projectsService->patchProjectStatusAndSorting($params, $handler);
} catch (\Leantime\Core\Exceptions\AuthorizationException $e) {
    // -32001: role or assignment missing — surface a permissions message, do not retry blindly
    $notify->error($e->getMessage());
}

Prevention

When it happens

Trigger: A user below manager dragging project cards between status columns; a manager re-sorting a project they are not assigned to; a payload that still contains project ids the caller lost access to after a role/assignment change.

Common situations: Drag-drop boards left open in a stale tab after the user's role was downgraded or assignment removed; organizations where managers manage only a subset of projects but the board lists all of them; scripts replaying a captured sort payload with a different account.

Related errors


AI-assisted analysis of Leantime/leantime@9a9f49f100 (2026-08-21). Data as JSON: /api/errors/b7c1c16db9cbfe5c. Report an issue: GitHub.