HKUDS/DeepTutor · error · ValueError
Capability not found
Error message
Capability not found: {resolved} What it means
A defensive invariant in `get_capability_contract`: after `resolve_capability` returned a canonical name, no manifest with that `name` was found in the registry. Normally unreachable (resolve checks the same manifests), so hitting it means the registry mutated between the two calls or manifests are inconsistent.
Solutions
- Retry the call — the registry may have been mid-mutation
- Audit for concurrent registration/unregistration and serialize registry access
- If using a custom ToolRegistry/CapabilityRegistry, ensure get_manifests() is consistent with resolution lookups
Defensive patterns
Strategy: retry
Validate before calling
contracts = {c["name"] for c in app.get_capability_contracts()}
if name not in contracts:
# registry in flux or stale; refresh/retry registration
... Try / catch
for attempt in range(3):
try:
return app.get_capability_contract(name)
except ValueError:
time.sleep(0.2 * (attempt + 1))
raise Prevention
- Avoid registering/unregistering capabilities concurrently with lookups
- Serialize registry mutations behind a lock in custom registries
When it happens
Trigger: Calling `app.get_capability_contract(name)` while another thread/task unregisters or reloads capabilities between `resolve_capability` and the manifest loop; or a registry implementation whose `get_manifests()` returns a filtered/different set than the one used for resolution.
Common situations: Concurrent capability hot-reload during a WebSocket turn; a custom registry subclass that filters manifests inconsistently; monkeypatched manifests in tests.
Related errors
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/f7090bb8e2edfd23.
Report an issue: GitHub.
Appendix: source
Thrown at deeptutor/app/facade.py:96
contracts = []
for manifest in self.capabilities.get_manifests():
contracts.append(
{
**manifest,
"availability": self.get_capability_availability(manifest["name"]).__dict__,
}
)
return contracts
def get_capability_contract(self, value: str) -> dict[str, Any]:
resolved = self.resolve_capability(value)
for manifest in self.capabilities.get_manifests():
if manifest["name"] == resolved:
return {
**manifest,
"availability": self.get_capability_availability(resolved).__dict__,
}
raise ValueError(f"Capability not found: {resolved}")
def get_capability_availability(self, capability: str) -> CapabilityAvailability:
resolved = self.resolve_capability(capability)
if resolved == "math_animator":
available = importlib.util.find_spec("manim") is not None
return CapabilityAvailability(
name=resolved,
available=available,
install_hint=(
""
if available
else "Install with `pip install -e '.[math-animator]'` "
"or `pip install -r requirements/math-animator.txt`."
),
)
return CapabilityAvailability(name=resolved, available=True)
async def start_turn(View on GitHub (pinned to 3e82f13042)