{"record":{"id":"23ae5dad57b65869","repo":"garrytan/gstack","slug":"cannot-delete-no-skill-for-normalized-in-sco","errorCode":null,"errorMessage":"Cannot delete: no skill for ${normalized} in ${scope} scope.\nCause: skill does not exist or is already tombstoned.\nAction: $B domain-skill list to see what exists.","messagePattern":"Cannot delete: no skill for (.+?) in (.+?) scope\\.\nCause: skill does not exist or is already tombstoned\\.\nAction: \\$B domain-skill list to see what exists\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"browse/src/domain-skills.ts","lineNumber":425,"sourceCode":"export async function listSkills(projectSlug: string): Promise<{ project: DomainSkillRow[]; global: DomainSkillRow[] }> {\n  const projectRows = await readRows(projectFile(projectSlug));\n  const globalRows = await readRows(globalFile());\n  const projectLatest = Array.from(resolveLatest(projectRows).values());\n  const globalLatest = Array.from(resolveLatest(globalRows).values()).filter((r) => r.state === 'global');\n  return { project: projectLatest, global: globalLatest };\n}\n\n/**\n * Tombstone a skill. Append a tombstone row; compactor cleans up later.\n */\nexport async function deleteSkill(host: string, projectSlug: string, scope: SkillScope = 'project'): Promise<void> {\n  const normalized = normalizeHost(host);\n  const file = scope === 'project' ? projectFile(projectSlug) : globalFile();\n  const rows = await readRows(file);\n  const latest = resolveLatest(rows);\n  const current = latest.get(`${scope}::${normalized}`);\n  if (!current) {\n    throw new Error(\n      `Cannot delete: no skill for ${normalized} in ${scope} scope.\\n` +\n        'Cause: skill does not exist or is already tombstoned.\\n' +\n        'Action: $B domain-skill list to see what exists.'\n    );\n  }\n  const tombstone: DomainSkillRow = {\n    ...current,\n    version: current.version + 1,\n    updated_ts: new Date().toISOString(),\n    tombstone: true,\n  };\n  await appendRow(file, tombstone);\n}\n","sourceCodeStart":407,"sourceCodeEnd":439,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/domain-skills.ts#L407-L439","documentation":"Thrown by deleteSkill() when resolveLatest(rows) has no entry for the key '<scope>::<normalized_host>'. This means the skill does not exist or was already tombstoned by a previous delete. deleteSkill appends a tombstone row, so double-deleting is an error.","triggerScenarios":"Calling deleteSkill(host, projectSlug, scope) when no non-tombstoned row exists for the host in that scope.","commonSituations":"Attempt to delete a skill that was already deleted (double-delete), wrong scope parameter (trying 'global' when skill is 'project'), or host name mismatch after normalization.","solutions":["Run '$B domain-skill list' to verify the skill still exists in the target scope","Check the scope argument — the skill may be in 'project' scope while you passed 'global' or vice versa","Verify host name spelling and normalization"],"exampleFix":"// before — deleting from wrong scope\nawait deleteSkill('example.com', 'my-proj', 'global'); // skill is in project scope\n\n// after — correct scope\nawait deleteSkill('example.com', 'my-proj', 'project');","handlingStrategy":"validation","validationCode":"// Check skill exists in target scope before deleting\nconst rows = await readRows(scope === 'project' ? projectFile(projectSlug) : globalFile());\nconst latest = resolveLatest(rows);\nconst key = `${scope}::${normalizeHost(host)}`;\nif (!latest.has(key)) {\n  console.error(`No skill for ${host} in ${scope} scope. Already deleted or never existed.`);\n  return;\n}\nawait deleteSkill(host, projectSlug, scope);","typeGuard":"function skillExistsInScope(latest: Map<string, DomainSkillRow>, host: string, scope: SkillScope): boolean {\n  return latest.has(`${scope}::${normalizeHost(host)}`);\n}","tryCatchPattern":null,"preventionTips":["Track deletion state in your application to avoid double-delete attempts","Verify the scope parameter matches where the skill actually lives (project vs global)","Call '$B domain-skill list' before delete to confirm existence"],"tags":["domain-skills","delete","not-found"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}