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

  1. 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
  2. If the cause is the 'Missing "Content-Location" header' error, check whether the reverse proxy forwards the Content-Location response header
  3. For admin tag operations, call confirmPassword() from @nextcloud/password-confirmation before createTag
  4. 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

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


AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17). Data as JSON: /api/errors/9a53276effacb207. Report an issue: GitHub.