fix(skills): surface skill-load failures instead of returning success#11408
Closed
zerone0x wants to merge 1 commit into
Closed
fix(skills): surface skill-load failures instead of returning success#11408zerone0x wants to merge 1 commit into
zerone0x wants to merge 1 commit into
Conversation
`build_skill_invocation_message()` returned a truthy placeholder string (`[Failed to load skill: ...]`) when a registered skill's `SKILL.md` could not be loaded. Every caller checked the result with `if msg:` to distinguish success from failure, so the placeholder string was treated as a successful invocation and silently fed into the agent as user prompt content. A missing/deleted/corrupt skill therefore looked like a working slash command from the user's perspective. Make the function return `None` on load failure (matching the existing "unknown skill" path) and update the gateway and webhook callers to emit a real user-facing error / log instead of forwarding the bare slash command. The CLI handler and `_handle_plan_command` already had dead `if not msg:` branches that now actually fire on load failure. Adds a regression test that scans a skill, deletes its SKILL.md before invocation, and asserts `None` is returned. Fixes #11200 Co-Authored-By: Claude <noreply@anthropic.com>
This was referenced Apr 23, 2026
Collaborator
This was referenced Apr 25, 2026
Contributor
Author
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #11200
Problem
build_skill_invocation_message()returned a truthy placeholder string ([Failed to load skill: <name>]) when a registered skill'sSKILL.mdcould not be loaded (e.g. file deleted or corrupted between scan and invocation). Every caller usedif msg:to distinguish success from failure, so the placeholder was treated as a successful invocation and silently fed into the agent as user prompt content. A missing/deleted/corrupt skill therefore looked like a working slash command from the user's perspective, while the model received[Failed to load skill: ...]as conversation input.Affected call sites flagged in the bug report:
agent/skill_commands.py:311-313cli.py:5571-5580gateway/run.py:2877-2882gateway/platforms/webhook.py:383-388Fix
build_skill_invocation_message()now returnsNoneon load failure (matching the existing "unknown skill" path) and logs a warning with the cmd_key + skill_dir for diagnosis. The docstring is updated to document the new contract.gateway/run.py: when the slash command resolves to a registered skill but loading fails, return a real error message to the user (instead of silently falling through and sending the bare/cmdto the LLM as free text).gateway/platforms/webhook.py: when a configured route skill is registered but fails to load, log loudly at ERROR and skip that skill rather than injecting the placeholder string into the prompt.cli.pyalready hadif not msg:branches for both the skill slash handler and_handle_plan_command; those branches were effectively dead code under the old return contract and now fire correctly on real load failures.Reproduction
The reporter's reproduction now returns
Noneinstead of'[Failed to load skill: demo]':Tests
TestBuildSkillInvocationMessage::test_returns_none_when_payload_load_fails_after_scancovers the regression: scan a skill, delete itsSKILL.md, assertbuild_skill_invocation_messagereturnsNone.pytest tests/agent/test_skill_commands.py— 27 passed.pytest tests/gateway/test_webhook_integration.py— 4 passed.