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
- Run `task-master tags` (or call the tags() function) to list existing tags and use an exact name from that output.
- Check spelling and casing — tag keys are matched exactly against the tasks.json top-level keys.
- 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
- Fetch the live tag list (tags()) instead of caching tag names across runs.
- Treat missing-tag deletes as idempotent no-ops in automation.
- Normalize casing/whitespace of tag names at creation time to avoid mismatches.
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
- MFA_VERIFICATION_FAILED
- Failed to initialize services: ${(error as Error).message}
- Invalid format: ${options.format}. Valid formats are: text,
- Failed to fetch tasks from any tag. First error: ${failedTag
- ${authCheck.error}
AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29).
Data as JSON: /api/errors/c72b485b851848d4.
Report an issue: GitHub.