nextcloud/server · error · Error
Failed to create tag
Error message
Failed to create tag
What it means
The catch-all wrapper thrown by createTag() when the POST /systemtags request fails for any reason other than a 409 duplicate-name conflict. The original WebDAVClientError is attached as `cause`, so the real HTTP status (401/403/5xx) or network error is only visible through the cause chain. Note that the 'Missing "Content-Location" header' error is thrown inside the same try block, so a reverse proxy stripping that header also surfaces as this error.
Source
Thrown at apps/systemtags/src/services/api.ts:109
try {
const { headers } = await davClient.customRequest(path, {
method: 'POST',
data: tagToPost,
})
const contentLocation = headers.get('content-location')
if (contentLocation) {
emit('systemtags:tag:created', tag)
return parseIdFromLocation(contentLocation)
}
logger.error(t('systemtags', 'Missing "Content-Location" header'))
throw new Error(t('systemtags', 'Missing "Content-Location" header'))
} catch (error) {
if ((error as WebDAVClientError)?.response?.status === 409) {
logger.error(t('systemtags', 'A tag with the same name already exists'), { error })
throw new Error(t('systemtags', 'A tag with the same name already exists'), { cause: error })
}
logger.error(t('systemtags', 'Failed to create tag'), { error })
throw new Error(t('systemtags', 'Failed to create tag'), { cause: error })
}
}
/**
* Update a tag on the server.
*
* @param tag - The tag to update
*/
export async function updateTag(tag: TagWithId): Promise<void> {
const path = '/systemtags/' + tag.id
const data = `<?xml version="1.0"?>
<d:propertyupdate xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
<d:set>
<d:prop>
<oc:display-name>${tag.displayName}</oc:display-name>
<oc:user-visible>${tag.userVisible}</oc:user-visible>
<oc:user-assignable>${tag.userAssignable}</oc:user-assignable>
<nc:color>${tag?.color || null}</nc:color>View on GitHub (pinned to ecdeb153ff)
Solutions
- Inspect (error.cause as WebDAVClientError)?.response?.status: 401 → re-authenticate / run confirmPassword(); 403 → the user lacks rights to create this tag; 5xx → check the Nextcloud server log
- If the cause is the 'Missing "Content-Location" header' error, check whether the reverse proxy forwards the Content-Location response header
- For admin tag operations, call confirmPassword() from @nextcloud/password-confirmation before createTag
- Retry once after re-login when the cause status is 401
Example fix
// before
try {
await createTag(tag)
} catch (e) {
console.error(e.message) // 'Failed to create tag' — real reason hidden
}
// after
try {
await createTag(tag)
} catch (e) {
const status = (e.cause as WebDAVClientError)?.response?.status
if (status === 401) await confirmPassword() // then retry
else if (status === 403) showError(t('systemtags', 'You are not allowed to create this tag'))
else throw e
} Defensive patterns
Strategy: try-catch
Try / catch
try {
const id = await createTag(tag)
} catch (error) {
const cause = error.cause as WebDAVClientError | undefined
const status = cause?.response?.status
if (status === 401) { /* re-authenticate / confirmPassword(), then retry once */ }
else if (status === 403) { /* user lacks rights for this tag */ }
else if (error.message.includes('Content-Location')) { /* proxy strips the header */ }
else throw error
} Prevention
- Call confirmPassword() before admin-level tag operations
- Ensure the reverse proxy forwards the Content-Location response header
- Handle session-expiry centrally in the DAV client so 401s re-prompt login instead of surfacing here
- Log error.cause, not just error.message — the status code lives in the cause chain
When it happens
Trigger: POST /systemtags returning non-409: 401 (expired session), 403 (a non-admin creating a tag that is not user-assignable), 503 (maintenance mode), or a network failure. Also triggered when the response omits the Content-Location header (header stripped by proxy, non-conforming server version), because that inner throw is re-caught and re-wrapped here.
Common situations: Session expired while the tag dialog was open; user without admin rights trying to create a non-assignable/invisible tag; reverse proxies (nginx with header filtering) dropping Content-Location; server in maintenance mode during an upgrade; dev environment pointed at a server that predates the Content-Location behavior.
Related errors
- Failed to update tag
- Failed to delete tag
- Failed to load tags for file
- Failed to set tag for file
- Failed to delete tag for file
AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17).
Data as JSON: /api/errors/9a53276effacb207.
Report an issue: GitHub.