nextcloud/server · error · Error

Failed to set tag for file

Error message

Failed to set tag for file

What it means

Thrown by setTagForFile() when the PUT to /systemtags-relations/files/{fileId}/{tagId} fails. This operation attaches an existing tag to a file, and the server enforces both file access and the tag's can-assign permission; failures are wrapped with the original WebDAVClientError as `cause`.

Source

Thrown at apps/systemtags/src/services/files.ts:69

}

/**
 * Set a tag for a given file (by id).
 *
 * @param tag - The tag to set
 * @param fileId - The id of the file to set the tag for
 */
export async function setTagForFile(tag: TagWithId | ServerTagWithId, fileId: number): Promise<void> {
	const path = '/systemtags-relations/files/' + fileId + '/' + tag.id
	const tagToPut = formatTag(tag)
	try {
		await davClient.customRequest(path, {
			method: 'PUT',
			data: tagToPut,
		})
	} catch (error) {
		logger.error(t('systemtags', 'Failed to set tag for file'), { error })
		throw new Error(t('systemtags', 'Failed to set tag for file'), { cause: error })
	}
}

/**
 * Delete a tag for a given file (by id).
 *
 * @param tag - The tag to delete
 * @param fileId - The id of the file to delete the tag for
 */
export async function deleteTagForFile(tag: TagWithId, fileId: number): Promise<void> {
	const path = '/systemtags-relations/files/' + fileId + '/' + tag.id
	try {
		await davClient.deleteFile(path)
	} catch (error) {
		logger.error(t('systemtags', 'Failed to delete tag for file'), { error })
		throw new Error(t('systemtags', 'Failed to delete tag for file'), { cause: error })
	}
}

View on GitHub (pinned to ecdeb153ff)

Solutions

  1. Pre-check the tag's canAssign/userAssignable flag from fetchTags() and hide or disable non-assignable tags in the picker
  2. Verify both ids are current (file node from the active view, tag from a fresh fetchTags())
  3. Inspect error.cause status: 403 → permission, 404 → stale id, 401 → re-login
  4. For admin-only tags run confirmPassword() before the DAV call

Example fix

// before
await setTagForFile(tag, fileId) // 403 if tag is not user-assignable

// after
if (!tag.canAssign && !isAdmin) {
	showError(t('systemtags', 'You are not allowed to assign this tag'))
} else {
	await setTagForFile(tag, fileId)
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check assignability — fetchTags returns oc:can-assign per tag
import { fetchTags, setTagForFile } from './services'

async function assignTagSafely(tag: TagWithId, fileId: number) {
	const fresh = (await fetchTags()).find((t) => t.id === tag.id)
	if (!fresh) throw new Error('stale tag id')
	if (!fresh.userAssignable) {
		throw new Error('tag is not assignable by users')
	}
	await setTagForFile(fresh, fileId)
}

Try / catch

try {
	await setTagForFile(tag, fileId)
} catch (error) {
	const status = (error.cause as WebDAVClientError | undefined)?.response?.status
	if (status === 403) { /* can-assign denied */ }
	else if (status === 404) { /* file or tag gone — refresh */ }
	else throw error
}

Prevention

When it happens

Trigger: PUT failing with 403 when the tag is not user-assignable (oc:user-assignable / oc:can-assign false for this user), 404 when either fileId or tagId no longer exists, 401 after session expiry, or 5xx in maintenance mode.

Common situations: Assigning an admin-only (non-assignable) tag as a regular user; tagging a file that was just deleted or whose share expired; stale tag id from an old tag list; concurrent removal of the tag in another session.

Related errors


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