{"record":{"id":"08485f0b9cd2e86c","repo":"passbolt/passbolt_api","slug":"the-resource-identifier-should-be-a-valid-uuid-08485f","errorCode":null,"errorMessage":"The resource identifier should be a valid UUID.","messagePattern":"The resource identifier should be a valid UUID\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"src/Controller/Favorites/FavoritesAddController.php","lineNumber":43,"sourceCode":"class FavoritesAddController extends AppController\n{\n    /**\n     * Mark a resource as favorite.\n     *\n     * @param string $foreignKey The identifier of the instance to mark as favorite.\n     * @throws \\Cake\\Http\\Exception\\BadRequestException If the resource id is not valid\n     * @throws \\Cake\\Http\\Exception\\NotFoundException If the resource does not exist\n     * @throws \\Cake\\Http\\Exception\\NotFoundException If the resource is soft deleted\n     * @throws \\Cake\\Http\\Exception\\NotFoundException If the user does not have access to the resource\n     * @return void\n     */\n    public function add(string $foreignKey)\n    {\n        $this->assertJson();\n\n        // Check request sanity\n        if (!Validation::uuid($foreignKey)) {\n            throw new BadRequestException(__('The resource identifier should be a valid UUID.'));\n        }\n\n        $result = (new FavoritesAddService())->add($this->User->getAccessControl(), $foreignKey);\n\n        $this->success(__('The resource was marked as favorite.'), $result);\n    }\n}\n","sourceCodeStart":25,"sourceCodeEnd":51,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Controller/Favorites/FavoritesAddController.php#L25-L51","documentation":"FavoritesAddController::add validates the $foreignKey path parameter with Cake's Validation::uuid() before marking the resource as favorite, throwing a BadRequestException (HTTP 400) if it is not a valid UUID. Favorites can only attach to resources identified by UUID.","triggerScenarios":"POST /favorites/<foreignKey>.json where <foreignKey> is not a UUID — e.g. a numeric id, a resource name, an empty string, or a truncated identifier.","commonSituations":"Clients storing integer ids from a different backend; slugs or labels pasted instead of ids; copy/paste truncating the UUID; old API versions that used numeric ids.","solutions":["Fetch the resource id from the resource list endpoint and use its full 36-character UUID in the URL.","Validate the id client-side against the UUID regex before calling.","Check for truncation/whitespace when copying the id.","Use the correct route — the favorite endpoint expects the favorited resource's id, not the favorite id."],"exampleFix":"// before\nPOST /favorites/123.json\n// after\nPOST /favorites/8e3874ae-4b40-590b-bdc4-af70aa7202b3.json","handlingStrategy":"validation","validationCode":"const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nif (!UUID_RE.test(resourceId)) {\n  throw new Error(`Resource id must be a UUID, got: ${resourceId}`);\n}","typeGuard":"function isUuid(v: unknown): v is string {\n  return typeof v === 'string' &&\n    /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v);\n}","tryCatchPattern":"try {\n  await api.post(`/favorites/${resourceId}.json`);\n} catch (e) {\n  if (e.response?.status === 400) {\n    // re-fetch the resource list to obtain a valid UUID\n  }\n  throw e;\n}","preventionTips":["Always resolve resource ids from the API, never user input","Validate UUID format before building URLs","Guard against truncation when copying ids"],"tags":["http-400","uuid","validation"],"backgroundTag":"invalid-identifier-format","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"}