eyaltoledano/claude-task-master · error · Error

Tag ${tag} not found

Error message

Tag ${tag} not found

What it means

deleteTag, operating on a legacy-format tasks.json, deletes the given tag key only if it exists; otherwise it throws this plain Error. Tag names act as top-level keys, and deleting a nonexistent key would silently no-op, so the library makes the absence explicit.

Source

Thrown at packages/tm-core/src/modules/storage/adapters/file-storage/file-storage.ts:730

			let shouldDeleteFile = false;

			await this.fileOps.modifyJson(filePath, (data: any) => {
				if (
					this.formatHandler.detectFormat(data) !== 'legacy' &&
					tag === 'master'
				) {
					// Standard format - mark for file deletion after lock release
					shouldDeleteFile = true;
					return data; // Return unchanged, we'll delete the file after
				}

				if (this.formatHandler.detectFormat(data) === 'legacy') {
					// Legacy format - remove the tag key
					if (tag in data) {
						delete data[tag];
						return data;
					} else {
						throw new Error(`Tag ${tag} not found`);
					}
				} else {
					throw new Error(`Tag ${tag} not found in standard format`);
				}
			});

			// Delete the file if we're removing master tag from standard format
			if (shouldDeleteFile) {
				await this.fileOps.deleteFile(filePath);
			}
		} catch (error: any) {
			if (error.code === 'ENOENT') {
				throw new Error(`Tag ${tag} not found - file doesn't exist`);
			}
			throw error;
		}
	}

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Enumerate tags first (getTagsWithStats) and only delete when the tag is present.
  2. Catch the error and treat it as success if your workflow requires idempotent deletion.
  3. Verify exact tag spelling and case — keys are matched with the 'in' operator, so case matters.
  4. Confirm the file is in legacy format; in standard format only 'master' can be deleted this way.

Example fix

// before
await storage.deleteTag('old-tag');
// after
const { tags } = await storage.getTagsWithStats();
if (tags.some((t) => t.name === 'old-tag')) {
  await storage.deleteTag('old-tag');
}
Defensive patterns

Strategy: try-catch

Validate before calling

const { tags } = await storage.getTagsWithStats();
if (!tags.some((t) => t.name === tag)) return; // nothing to delete

Type guard

function hasTag(tagList: Array<{ name: string }>, name: string): boolean {
  return tagList.some((t) => t.name === name);
}

Try / catch

try {
  await storage.deleteTag(tag);
} catch (err) {
  if (err instanceof Error && err.message === `Tag ${tag} not found`) {
    return; // idempotent delete
  }
  throw err;
}

Prevention

When it happens

Trigger: storage.deleteTag('old-tag') when 'old-tag' is not a key in the legacy tasks.json; deleting a tag already removed by another process; deleting with different casing than the stored key; calling deleteTag for 'master' while the file is in standard format is a different path (see error 216).

Common situations: Cleanup scripts running twice; stale tag lists cached from before a teammate deleted the tag; case-sensitivity mismatches between tag references; tags lost after a manual file edit or merge conflict resolution.

Related errors


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