eyaltoledano/claude-task-master · error · Error

Tag "${tagName}" does not exist

Error message

Tag "${tagName}" does not exist

What it means

After loading and normalizing the tagged data, deleteTag() looks up rawData[tagName]. If no tag with that exact name exists in tasks.json, it throws this error. Tag lookups are exact string matches, so case or whitespace differences also count as nonexistent.

Source

Thrown at scripts/modules/task-manager/tag-management.js:313

						created: new Date().toISOString(),
						updated: new Date().toISOString(),
						description: 'Tasks live here by default'
					}
				}
			};
		} else {
			// This is already in tagged format, use it directly but exclude internal fields
			rawData = {};
			for (const [key, value] of Object.entries(data)) {
				if (key !== '_rawTaggedData' && key !== 'tag') {
					rawData[key] = value;
				}
			}
		}

		// Check if tag exists
		if (!rawData[tagName]) {
			throw new Error(`Tag "${tagName}" does not exist`);
		}

		// Get current tag to check if we're deleting the active tag
		const currentTag = getCurrentTag(projectRoot);
		const isCurrentTag = currentTag === tagName;

		// Get task count for confirmation
		const tasks = getTasksForTag(rawData, tagName);
		const taskCount = tasks.length;

		// If not forced and has tasks, require confirmation (for CLI)
		if (!yes && taskCount > 0 && outputFormat === 'text') {
			console.log(
				boxen(
					chalk.yellow.bold('⚠ WARNING: Tag Deletion') +
						`\n\nYou are about to delete tag "${chalk.cyan(tagName)}"` +
						`\nThis will permanently delete ${chalk.red.bold(taskCount)} tasks` +
						'\n\nThis action cannot be undone!',

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Run `task-master tags` (or call the tags() function) to list existing tags and use an exact name from that output.
  2. Check spelling and casing — tag keys are matched exactly against the tasks.json top-level keys.
  3. Make the deletion conditional: skip or no-op when the tag is absent instead of treating it as fatal.

Example fix

// before
await deleteTag(tasksPath, 'Feature_X', options, context);
// after
const { tags } = await tags(tasksPath, context);
if (tags.some((t) => t.name === 'feature-x')) {
  await deleteTag(tasksPath, 'feature-x', options, context);
}
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'fs';
const data = JSON.parse(fs.readFileSync(tasksPath, 'utf8'));
if (!data[tagName]) {
  throw new Error(`Tag "${tagName}" does not exist; available: ${Object.keys(data).filter(k => !k.startsWith('_')).join(', ')}`);
}

Try / catch

try {
  await deleteTag(tasksPath, tag, opts, ctx);
} catch (e) {
  if (e.message.includes('does not exist')) {
    console.warn(`Tag "${tag}" already absent; treating delete as no-op`);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling deleteTag with a tag name that was never created, a typo'd or case-mismatched name ('Backend' vs 'backend'), deleting a tag that was already removed, or operating on a stale tasksPath that doesn't contain the tag.

Common situations: Scripts iterating over a cached/old tag list after another process deleted tags, users typing tag names from memory, CI pipelines referencing a tag only present in another environment's tasks.json.

Related errors


AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29). Data as JSON: /api/errors/c72b485b851848d4. Report an issue: GitHub.