{"record":{"id":"91ad09b6fac6bb04","repo":"passbolt/passbolt_api","slug":"invalid-order-inner-message","errorCode":null,"errorMessage":"Invalid order. {inner message}","messagePattern":"Invalid order\\. (.+?)","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"src/Controller/Component/QueryStringComponent.php","lineNumber":251,"sourceCode":"     * @return bool true if validate\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if a validation error occurs\n     */\n    public static function validateQueryItems(array $query, array $allowedQueryItems, array $filterValidators): bool\n    {\n        foreach ($query as $key => $parameters) {\n            switch ($key) {\n                case 'filter':\n                    try {\n                        self::validateFilters($parameters, $filterValidators);\n                    } catch (CakeException $e) {\n                        throw new BadRequestException(__('Invalid filter.') . ' ' . $e->getMessage());\n                    }\n                    break;\n                case 'order':\n                    try {\n                        self::validateOrders($parameters, $allowedQueryItems);\n                    } catch (CakeException $e) {\n                        throw new BadRequestException(__('Invalid order.') . ' ' . $e->getMessage());\n                    }\n                    break;\n                case 'contain':\n                    try {\n                        self::validateContain($parameters);\n                    } catch (CakeException $e) {\n                        throw new BadRequestException(__('Invalid contain.') . ' ' . $e->getMessage());\n                    }\n                    break;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Validate filters\n     *","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Controller/Component/QueryStringComponent.php#L233-L269","documentation":"Thrown by QueryStringComponent::validateQueryItems when validating the 'order' query string key. validateOrders() checks each sort field against the controller's $allowedQueryItems whitelist; on failure the CakeException is re-thrown as a BadRequestException prefixed with 'Invalid order.' plus the inner reason. It means the client requested sorting on a field that is not allowed for this endpoint.","triggerScenarios":"GET requests with ?order[...] naming a field absent from the controller's allowed query items, or a direction other than ASC/DESC, e.g. ?order[Resource.username]=ASCENDING or sorting a non-whitelisted property.","commonSituations":"Clients sorting on fields removed/renamed in a passbolt version; hand-built URLs guessing field names; front-end table sort columns not matching the API's allowed order fields; case mismatches in field names.","solutions":["Read the inner message after 'Invalid order.' to see which field/direction was rejected.","Use only fields listed in the endpoint's allowed query items (see the controller's QueryStringComponent config).","Use ASC or DESC as the sort direction only.","Drop the order clause to get the API default sort.","If the field should be sortable, add it to $allowedQueryItems for that controller action."],"exampleFix":"// before\nGET /users.json?order[User.profil]=ASC\n// after\nGET /users.json?order[User.profile]=ASC","handlingStrategy":"validation","validationCode":"$allowedOrderFields = ['User.username','User.created','User.modified','Profile.first_name','Resource.name','Resource.created','Resource.modified']; // per endpoint\nforeach ((array)($query['order'] ?? []) as $field => $direction) {\n    $dir = strtoupper((string)$direction);\n    if (!in_array($dir, ['ASC','DESC'], true)) {\n        throw new InvalidArgumentException(\"Invalid order direction: $direction\");\n    }\n    if (!in_array($field, $allowedOrderFields, true)) {\n        throw new InvalidArgumentException(\"Field not sortable: $field\");\n    }\n}","typeGuard":"function isValidOrderClause(mixed $order, array $allowed): bool {\n    if (!is_array($order) || $order === []) return false;\n    foreach ($order as $field => $dir) {\n        if (!in_array($field, $allowed, true)) return false;\n        if (!in_array(strtoupper((string)$dir), ['ASC','DESC'], true)) return false;\n    }\n    return true;\n}","tryCatchPattern":"try {\n    $result = $api->get('/users.json', ['query' => ['order' => $order]]);\n} catch (BadRequestException $e) {\n    if (str_starts_with($e->getMessage(), 'Invalid order.')) {\n        $result = $api->get('/users.json'); // fall back to default sort\n    } else {\n        throw $e;\n    }\n}","preventionTips":["Only sort on fields returned in the endpoint response and documented as sortable","Always use ASC/DESC (uppercase) as direction","Fetch the endpoint's allowed query items from docs or the controller before adding sort columns","Update client sort mappings when upgrading passbolt versions","Unit-test generated order clauses against the API in CI"],"tags":["http","bad-request","query-string","validation","sorting"],"backgroundTag":"invalid-query-parameter","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}