eyaltoledano/claude-task-master · error · Error
Tag ${oldTag} not found
Error message
Tag ${oldTag} not found What it means
renameTag, on a legacy-format tasks.json, renames the tag key only when oldTag is an existing key; otherwise it throws this error. Renaming requires the source tag to exist since the operation moves its tasks and metadata to the new key.
Source
Thrown at packages/tm-core/src/modules/storage/adapters/file-storage/file-storage.ts:771
async renameTag(oldTag: string, newTag: string): Promise<void> {
const filePath = this.pathResolver.getTasksPath();
try {
await this.fileOps.modifyJson(filePath, (existingData: any) => {
if (this.formatHandler.detectFormat(existingData) === 'legacy') {
// Legacy format - rename the tag key
if (oldTag in existingData) {
existingData[newTag] = existingData[oldTag];
delete existingData[oldTag];
// Update metadata tags array
if (existingData[newTag].metadata) {
existingData[newTag].metadata.tags = [newTag];
}
return existingData;
} else {
throw new Error(`Tag ${oldTag} not found`);
}
} else if (oldTag === 'master') {
// Convert standard format to legacy when renaming master
const masterTasks = existingData.tasks || [];
const masterMetadata = existingData.metadata || {};
return {
[newTag]: {
tasks: masterTasks,
metadata: { ...masterMetadata, tags: [newTag] }
}
};
} else {
throw new Error(`Tag ${oldTag} not found in standard format`);
}
});
} catch (error: any) {
if (error.code === 'ENOENT') {View on GitHub (pinned to c0c98d367c)
Solutions
- Verify the source tag exists (getTagsWithStats) before renaming.
- If the error occurs because a previous rename already succeeded, treat it as done — check whether newTag now exists.
- Match exact spelling/case of the stored tag key.
- If the file is standard format, only 'master' can be the rename source; migrate or rename master instead.
Example fix
// before
await storage.renameTag('old-name', 'new-name');
// after
const { tags } = await storage.getTagsWithStats();
if (tags.some((t) => t.name === 'old-name')) {
await storage.renameTag('old-name', 'new-name');
} else if (tags.some((t) => t.name === 'new-name')) {
// already renamed previously — no-op
} Defensive patterns
Strategy: validation
Validate before calling
const { tags } = await storage.getTagsWithStats();
if (!tags.some((t) => t.name === oldTag)) {
throw new Error(`Cannot rename: tag '${oldTag}' does not exist`);
} Type guard
function canRename(tagList: Array<{ name: string }>, oldTag: string): boolean {
return tagList.some((t) => t.name === oldTag);
} Try / catch
try {
await storage.renameTag(oldTag, newTag);
} catch (err) {
if (err instanceof Error && err.message === `Tag ${oldTag} not found`) {
const { tags } = await storage.getTagsWithStats();
if (tags.some((t) => t.name === newTag)) return; // rename already happened
throw err;
}
throw err;
} Prevention
- Check source-tag existence before renaming; renames are not idempotent.
- Handle re-run scenarios by detecting that newTag already exists.
- Use exact tag spelling/case — key matching is case-sensitive.
- Serialize tag mutations across processes/teammates to avoid stale-name races.
When it happens
Trigger: storage.renameTag('old-name', 'new-name') when 'old-name' is not a key in the legacy file; renaming a tag after it was deleted or renamed by someone else; casing mismatch between the passed name and stored key; renaming a non-master tag while the file is standard format takes the other branch (see 219).
Common situations: Rename scripts run twice (second run's source no longer exists); tag renamed by a teammate concurrently; typos or case differences in tag names; tag list stale after merging branches that both touched tasks.json.
Related errors
- Tag ${tag} not found
- Tag ${oldTag} not found
- Failed to move file from ${oldPath} to ${newPath}: ${error.m
- Parent task ${parentId} not found
- Subtask ${subtaskId} not found in parent task ${parentId}
AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29).
Data as JSON: /api/errors/f9b97f10bb7b5f0a.
Report an issue: GitHub.