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

  1. Verify the source tag exists (getTagsWithStats) before renaming.
  2. If the error occurs because a previous rename already succeeded, treat it as done — check whether newTag now exists.
  3. Match exact spelling/case of the stored tag key.
  4. 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

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


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