{"record":{"id":"db5a1fe05b5d68f0","repo":"nextcloud/server","slug":"failed-to-delete-tag","errorCode":null,"errorMessage":"Failed to delete tag","messagePattern":"Failed to delete tag","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/systemtags/src/services/api.ts","lineNumber":156,"sourceCode":"\t} catch (error) {\n\t\tlogger.error(t('systemtags', 'Failed to update tag'), { error })\n\t\tthrow new Error(t('systemtags', 'Failed to update tag'), { cause: error })\n\t}\n}\n\n/**\n * Delete a tag.\n *\n * @param tag - The tag to delete\n */\nexport async function deleteTag(tag: TagWithId): Promise<void> {\n\tconst path = '/systemtags/' + tag.id\n\ttry {\n\t\tawait davClient.deleteFile(path)\n\t\temit('systemtags:tag:deleted', tag)\n\t} catch (error) {\n\t\tlogger.error(t('systemtags', 'Failed to delete tag'), { error })\n\t\tthrow new Error(t('systemtags', 'Failed to delete tag'), { cause: error })\n\t}\n}\n\ntype TagObject = {\n\tid: number\n\ttype: string\n}\n\ntype TagObjectResponse = {\n\tetag: string\n\tobjects: TagObject[]\n}\n\n/**\n * Get the objects for a tag.\n *\n * @param tag - The tag to get the objects for\n * @param type - The type of the objects","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/systemtags/src/services/api.ts#L138-L174","documentation":"Thrown by deleteTag() when the DELETE request on /systemtags/{id} fails. Deleting a system tag is an instance-wide operation with permission requirements, and any DAV failure (401/403/404/5xx or network) is wrapped into this error with the original WebDAVClientError as `cause`.","triggerScenarios":"DELETE /systemtags/{tagId} failing: 403 (the user lacks admin rights to delete the tag — deleting affects every user since tags are global), 404 (tag already removed elsewhere), 401 (expired session), 503 (maintenance mode), or connectivity loss.","commonSituations":"Non-admin attempting to delete a global tag from the tag management UI; the tag already deleted from another session (stale list); removing a tag that files still carry; server in maintenance during upgrade.","solutions":["Check (error.cause as WebDAVClientError)?.response?.status: treat 404 as already-deleted (refresh the list and continue), 403 as missing permission, 401 as session expiry","Verify the tag still exists with fetchTag(tag.id) before showing a destructive confirmation dialog","For admin operations ensure confirmPassword() ran before the DAV call","Check the server log if the cause status is 5xx"],"exampleFix":"// before\nawait deleteTag(tag) // unhandled 404 when tag was already deleted\n\n// after\ntry {\n\tawait deleteTag(tag)\n} catch (e) {\n\tif ((e.cause as WebDAVClientError)?.response?.status === 404) {\n\t\t// already gone — remove from UI and move on\n\t\temit('systemtags:tag:deleted', tag)\n\t} else throw e\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n\tawait deleteTag(tag)\n} catch (error) {\n\tconst status = (error.cause as WebDAVClientError | undefined)?.response?.status\n\tif (status === 404) {\n\t\t// already deleted — treat as success and update the UI\n\t} else throw error\n}","preventionTips":["Treat 404 as idempotent success — the goal state (tag absent) already holds","Confirm delete permission (admin rights) before showing the destructive action","Call confirmPassword() before admin DAV deletes"],"tags":["systemtags","webdav","delete","typescript"],"backgroundTag":"webdav-delete-failed","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}