{"record":{"id":"86defee42556dfc1","repo":"can1357/oh-my-pi","slug":"unknown-skill-rawskillsegment-available-av","errorCode":null,"errorMessage":"Unknown skill: ${rawSkillSegment}. Available: ${availableStr}","messagePattern":"Unknown skill: (.+?)\\. Available: (.+?)","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/bash-skill-urls.ts","lineNumber":77,"sourceCode":"\tlet rawSkillSegment = parsed[1];\n\tif (!rawSkillSegment) {\n\t\tthrow new ToolError(`skill:// URL requires a skill name: ${url}`);\n\t}\n\t// Decode percent-encoded colons (%3A) used for namespaced skill names\n\ttry {\n\t\trawSkillSegment = decodeURIComponent(rawSkillSegment);\n\t} catch {\n\t\t// Leave as-is if decoding fails\n\t}\n\n\t// Resolve skill name by longest-prefix match against registered skills.\n\t// This handles namespaced skills (\"plugin:skill\") where the URI may also\n\t// carry a colon-delimited suffix (e.g., \":1-5\" line range).\n\tconst { skill, suffix } = matchSkillName(rawSkillSegment, skills);\n\tif (!skill) {\n\t\tconst available = skills.map(s => s.name);\n\t\tconst availableStr = available.length > 0 ? available.join(\", \") : \"none\";\n\t\tthrow new ToolError(`Unknown skill: ${rawSkillSegment}. Available: ${availableStr}`);\n\t}\n\n\t// Combine any colon suffix (line range like \":1-5\") with the path segment\n\tconst rawPath = (parsed[2] ?? \"\") + (suffix ? `/${suffix}` : \"\");\n\tconst hasRelativePath = rawPath !== \"\" && rawPath !== \"/\";\n\n\tif (!hasRelativePath) {\n\t\treturn path.resolve(skill.baseDir);\n\t}\n\n\tlet relativePath: string;\n\ttry {\n\t\trelativePath = decodeURIComponent(rawPath.slice(1));\n\t} catch {\n\t\tthrow new ToolError(`Invalid skill:// URL path encoding: ${url}`);\n\t}\n\ttry {\n\t\tvalidateRelativePath(relativePath);","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/bash-skill-urls.ts#L59-L95","documentation":"The skill name inside the skill:// URL did not match any registered skill. matchSkillName compares the (decoded, suffix-stripped) segment against known Skill names; on no match the error lists every available name so the caller can self-correct. Namespaced names like \"plugin:skill\" and colon line-range suffixes like \":1-5\" are handled during matching.","triggerScenarios":"Calling resolveSkillUrlToPath(\"skill://typo-name/SKILL.md\", skills) where \"typo-name\" matches no skill in the passed Skill[] — name misspelled, skill not loaded, wrong namespace prefix (missing \"plugin:\"), or a stale name after a plugin rename.","commonSituations":"A model invents a skill name; the user renamed or uninstalled a plugin skill; the skills array passed to the resolver is empty or filtered so a legitimately loaded skill looks unknown; colon-in-name edge cases where the suffix stripper eats part of the name.","solutions":["Use exactly one of the names listed in the error's \"Available: ...\" list.","Confirm the skill/plugin is actually loaded and enabled before referencing it.","If namespaced, include the full \"plugin:skill\" name (URL-encode the colon as %3A if needed).","Re-fetch the current skill list — the registry may have changed since the URL was built."],"exampleFix":"// before\nresolveSkillUrlToPath(\"skill://code-review/SKILL.md\", skills);\n// Unknown skill: code-review. Available: plugin:review\n\n// after\nresolveSkillUrlToPath(\"skill://plugin%3Areview/SKILL.md\", skills);","handlingStrategy":"validation","validationCode":"const name = decodeURIComponentSafe(nameSegment);\nif (!skills.some(s => s.name === name)) {\n  throw new Error(`unknown skill '${name}'; available: ${skills.map(s => s.name).join(\", \")}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  return resolveSkillUrlToPath(url, skills);\n} catch (e) {\n  if (e instanceof ToolError && e.message.startsWith(\"Unknown skill\")) {\n    // parse 'Available:' list, pick closest match or report options to the user\n  } else throw e;\n}","preventionTips":["Always source skill names from the live registry, not memory or hardcoded lists.","Fuzzy-match the requested name against skills before resolving and suggest corrections.","Re-check plugin load state when a previously working URL starts failing."],"tags":["skills","name-resolution","validation"],"backgroundTag":"unknown-resource-name","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}