eyaltoledano/claude-task-master · error · Error
Tag "${tagName}" already exists
Error message
Tag "${tagName}" already exists What it means
Before writing, createTag checks the raw tagged data for an existing entry under the requested tagName. Duplicate tag names are not allowed, so attempting to create a tag that already exists throws this error. Names are compared as exact keys in the raw data object.
Source
Thrown at scripts/modules/task-manager/tag-management.js:139
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 already exists
if (rawData[tagName]) {
throw new Error(`Tag "${tagName}" already exists`);
}
// Determine source for copying tasks (only if explicitly requested)
let sourceTasks = [];
if (copyFromCurrent || copyFromTag) {
const sourceTag = copyFromTag || getCurrentTag(projectRoot);
sourceTasks = getTasksForTag(rawData, sourceTag);
if (copyFromTag && sourceTasks.length === 0) {
logFn.warn(`Source tag "${copyFromTag}" not found or has no tasks`);
}
logFn.info(`Copying ${sourceTasks.length} tasks from tag "${sourceTag}"`);
} else {
logFn.info('Creating empty tag (no tasks copied)');
}
// Create the new tag structure in raw dataView on GitHub (pinned to c0c98d367c)
Solutions
- Check existing tags with 'task-master tags' and reuse the existing one
- If the goal is to copy/refresh, use a versioned name (sprint-1, sprint-2)
- In scripts, guard with an existence check before calling createTag
Example fix
// before
await createTag(tasksPath, 'sprint-1'); // throws if exists
// after
if (!rawData['sprint-1']) {
await createTag(tasksPath, 'sprint-1');
} Defensive patterns
Strategy: validation
Validate before calling
const raw = JSON.parse(fs.readFileSync(tasksPath, 'utf8'));
if (raw[tagName]) {
console.log(`Tag '${tagName}' already exists — reusing it`);
} else {
await createTag(tasksPath, tagName, {});
} Type guard
function tagIsNew(rawData, name) {
return Boolean(rawData) && !(name in rawData);
} Try / catch
try {
await createTag(tasksPath, name, {});
} catch (err) {
if (err.message.includes('already exists')) {
console.log(`Tag '${name}' exists; proceeding with the existing tag.`);
} else throw err;
} Prevention
- Make tag creation idempotent: check existence before creating
- List tags ('task-master tags') as a preflight step in scripts/CI
- Use versioned or date-suffixed tag names to avoid team collisions
- Skip creation steps on pipeline re-runs instead of blindly re-creating
When it happens
Trigger: Calling createTag with a name already present in tasks.json, e.g. re-running an idempotent-looking script, or creating 'feature-x' when 'feature-x' was created earlier; note the check is case-sensitive so 'Feature-X' would pass this check even if semantically similar.
Common situations: CI pipelines re-running tag creation steps without guards; team members independently creating the same sprint tag; automation deriving names that collide with existing tags.
Related errors
- VALIDATION_ERROR
- INVALID_TASKS_FILE
- Tag name is required and must be a string
- Tag name can only contain letters, numbers, hyphens, and und
- "${tagName}" is a reserved tag name
AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29).
Data as JSON: /api/errors/5c767fcd42b2040f.
Report an issue: GitHub.