{"record":{"id":"2f266a3026fa6baa","repo":"passbolt/passbolt_api","slug":"the-tag-id-is-not-valid","errorCode":null,"errorMessage":"The tag id is not valid.","messagePattern":"The tag id is not valid\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/Tags/src/Controller/Tags/TagsDeleteController.php","lineNumber":55,"sourceCode":"     * @inheritDoc\n     */\n    public function initialize(): void\n    {\n        parent::initialize();\n        $this->Tags = $this->fetchTable('Passbolt/Tags.Tags');\n        $this->ResourcesTags = $this->fetchTable('Passbolt/Tags.ResourcesTags');\n    }\n\n    /**\n     * Tag delete action\n     *\n     * @param string|null $id Id of the tag to delete\n     * @return void\n     */\n    public function delete(?string $id = null)\n    {\n        if (!Validation::uuid($id)) {\n            throw new BadRequestException(__('The tag id is not valid.'));\n        }\n\n        try {\n            /** @var \\Passbolt\\Tags\\Model\\Entity\\Tag $tag */\n            $tag = $this->Tags->get($id, contain: ['ResourcesTags']);\n        } catch (RecordNotFoundException $e) {\n            throw new NotFoundException(__('The tag does not exist.'));\n        }\n\n        if ($tag->get('is_shared')) {\n            throw new ForbiddenException(__('You do not have the permission to delete shared tags.'));\n        }\n\n        if (!$this->isPersonalTagAccessible($tag)) {\n            throw new NotFoundException(__('The tag does not exist.'));\n        }\n\n        $this->Tags->delete($tag);","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Tags/src/Controller/Tags/TagsDeleteController.php#L37-L73","documentation":"TagsDeleteController::delete() validates the tag id route parameter with Validation::uuid() and throws BadRequestException 'The tag id is not valid.' for non-UUID input, before attempting to load the tag. Separate handling (RecordNotFoundException) covers valid UUIDs that don't exist.","triggerScenarios":"DELETE /tags/<id> with a non-UUID id: numeric id, slug string, empty/null id, or malformed identifier.","commonSituations":"Client passing the tag slug (e.g. 'marketing') instead of the tag UUID; route segment missing so null is passed; using an id from a legacy non-UUID tag store.","solutions":["Look up the tag's UUID via GET /tags.json and delete using that id","Fix client code to send the UUID field, not the slug","Guard against null/empty ids client-side before issuing DELETE"],"exampleFix":"// before\nawait api.delete(`/tags/${tag.slug}`);\n// after\nif (!/^[0-9a-f-]{36}$/i.test(tag.id)) throw new Error('Tag id must be a UUID');\nawait api.delete(`/tags/${tag.id}`);","handlingStrategy":"validation","validationCode":"if (!isUuid(tagId)) throw new Error('tagId must be a UUID');","typeGuard":"const isUuid = (v) => typeof v === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v);","tryCatchPattern":"try { await api.delete(`/tags/${tagId}`); } catch (e) { if (e.status === 400) { /* id format wrong — use UUID from /tags.json */ } else throw e; }","preventionTips":["Use the tag UUID from GET /tags.json, never the slug","Handle missing route id segments (null) before calling","Validate all entity ids are UUIDs at the API client layer"],"tags":["passbolt","validation","uuid","tags"],"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"}