HKUDS/nanobot · error · RuntimeError
PyJWT not installed. Run: nanobot plugins enable msteams
Error message
PyJWT not installed. Run: nanobot plugins enable msteams
What it means
Guard in _validate_inbound_auth that the optional PyJWT dependency is missing, so inbound Bot Framework bearer tokens cannot be verified. The runtime gates on MSTEAMS_AVAILABLE because the MS Teams channel is an optional plugin; the faulty input is the environment (missing package), not the request.
Solutions
- Run 'nanobot plugins enable msteams' to install channel dependencies (PyJWT)
- Alternatively install PyJWT manually (e.g. 'pip install pyjwt[crypto]') and restart the gateway
- Verify installation with 'python -c "import jwt"'
Defensive patterns
Strategy: fallback
When it happens
Trigger: Thrown at nanobot/channels/msteams/runtime.py:475 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of HKUDS/nanobot@42f37dc4c0 (2026-08-26).
Data as JSON: /api/errors/7bbe855393668e16.
Report an issue: GitHub.
Appendix: source
Thrown at nanobot/channels/msteams/runtime.py:475
if quoted and reply and len(reply) <= 160:
return self._format_reply_with_quote(quoted, reply)
return cleaned
def _format_reply_with_quote(self, quoted: str, reply: str) -> str:
"""Format a reply-with-context message for the model without Teams wrapper noise."""
quoted = quoted.strip()
reply = reply.strip()
if quoted and reply:
return f"User is replying to: {quoted}\nUser reply: {reply}"
if reply:
return reply
return quoted
async def _validate_inbound_auth(self, auth_header: str, activity: dict[str, Any]) -> None:
"""Validate inbound Bot Framework bearer token."""
if not MSTEAMS_AVAILABLE:
raise RuntimeError("PyJWT not installed. Run: nanobot plugins enable msteams")
if not auth_header.lower().startswith("bearer "):
raise ValueError("missing bearer token")
token = auth_header.split(" ", 1)[1].strip()
if not token:
raise ValueError("empty bearer token")
header = jwt.get_unverified_header(token)
kid = str(header.get("kid") or "").strip()
if not kid:
raise ValueError("missing token kid")
jwks = await self._get_botframework_jwks()
keys = cast(list[dict[str, Any]], jwks.get("keys") or [])
jwk = next((key for key in keys if key.get("kid") == kid), None)
if not jwk:
raise ValueError(f"signing key not found for kid={kid}")View on GitHub (pinned to 42f37dc4c0)