{"record":{"id":"e9921b94f06f7a76","repo":"passbolt/passbolt_api","slug":"filter-0-is-not-valid","errorCode":null,"errorMessage":"Filter {0} is not valid.","messagePattern":"Filter (.+?) is not valid\\.","errorType":"validation","errorClass":"CakeException","httpStatus":400,"severity":"error","filePath":"src/Controller/Component/QueryStringComponent.php","lineNumber":353,"sourceCode":"                        break;\n                    case 'has-tag':\n                        self::validateFilterString($values, $filterName);\n                        break;\n                    case 'frequency':\n                        self::validateFilterInteger($values, $filterName);\n                        break;\n                    case 'metadata_key_type':\n                        self::validateFilterInList($values, $filterName, ['user_key', 'shared_key']);\n                        break;\n                    default:\n                        // Check if custom filter validators were defined for this filter\n                        if (!isset($filterValidators[$filterName])) {\n                            $msg = __('No validation rule for filter {0}. Please create one.', $filterName);\n                            throw new CakeException($msg);\n                        }\n\n                        if (!call_user_func($filterValidators[$filterName], $values)) {\n                            throw new CakeException(__('Filter {0} is not valid.', $filterName));\n                        }\n\n                        break;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Check if the filter is a valid string\n     *\n     * @param mixed $value to check\n     * @param string $filtername for error message display\n     * @throw CakeException if the filter is not valid\n     * @return bool true if the filter is valid\n     */","sourceCodeStart":335,"sourceCodeEnd":371,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Controller/Component/QueryStringComponent.php#L335-L371","documentation":"Raised inside QueryStringComponent::validateFilters() (surfaced as 'Invalid filter. Filter {name} is not valid.') when a custom filter validator registered in $filterValidators exists but its callable returned a falsy value for the submitted values. The filter name is known and allowed, but the value did not satisfy the custom rule.","triggerScenarios":"A request sends ?filter[custom-key]=value where the controller registered a validator for custom-key, and call_user_func($filterValidators[$filterName], $values) returns false — e.g. a validator expecting an array of UUIDs receives a single non-UUID string, or a comma-list validator gets an empty value.","commonSituations":"Validators written too strictly (failing on empty arrays, null, or single values when the API sends scalars); clients sending values in the wrong shape (array vs string) for custom filters; locale/encoding issues in string validators; API version drift between client expectations and server validator rules.","solutions":["Read the inner message to identify which custom filter failed.","Inspect the validator callable registered for that filter name and check what shape/format it expects.","Send the values in the format the validator expects (e.g. array of UUIDs, valid enum strings).","If the validator is wrong (too strict or mishandles scalar/array input), fix the callable to handle all legitimate input shapes.","Log the received $values server-side to reproduce the failing payload."],"exampleFix":"// before\n'case-ids' => function ($values) { return is_string($values); },\n// after\n'case-ids' => function ($values) {\n    $ids = (array)$values;\n    return $ids !== [] && count(array_filter($ids, 'ctype_xdigit')) === count($ids);\n},","handlingStrategy":"validation","validationCode":"// Mirror the server validator's expectations before calling the API\nfunction validateCaseIdsFilter(mixed $values): bool {\n    $ids = is_array($values) ? $values : [$values];\n    if ($ids === []) return false;\n    foreach ($ids as $id) {\n        if (!is_string($id) || !preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i', $id)) {\n            return false;\n        }\n    }\n    return true;\n}\nif (!validateCaseIdsFilter($filters['case-ids'])) {\n    throw new InvalidArgumentException('case-ids must be a non-empty list of UUIDs');\n}","typeGuard":"function isScalarOrUuidArray(mixed $values): bool {\n    return is_scalar($values) || (is_array($values) && array_is_list($values) && $values !== []);\n}","tryCatchPattern":"try {\n    $result = $api->get('/items.json', ['query' => ['filter' => $filters]]);\n} catch (BadRequestException $e) {\n    if (preg_match('/Filter (\\\\S+) is not valid\\\\./', $e->getMessage(), $m)) {\n        $logger->warning('Custom filter rejected', ['filter' => $m[1], 'values' => $filters[$m[1]] ?? null]);\n        unset($filters[$m[1]]);\n        $result = $api->get('/items.json', ['query' => ['filter' => $filters]]);\n    } else {\n        throw $e;\n    }\n}","preventionTips":["Write a client-side mirror of each server custom validator and keep them in sync","Make server validators tolerant of both scalar and single-element array input","Test custom filters with empty, single-value, and multi-value payloads","Log rejected values server-side to diagnose shape mismatches quickly","Document the expected value format next to each filterValidators registration"],"tags":["filters","validation","query-string","custom-validator"],"backgroundTag":"invalid-argument-value","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"}