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

  1. Run 'nanobot plugins enable msteams' to install channel dependencies (PyJWT)
  2. Alternatively install PyJWT manually (e.g. 'pip install pyjwt[crypto]') and restart the gateway
  3. 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)