HKUDS/nanobot · error · ImportError
Channel plugin ' ' runtime ' ' does not resolve to a…
Error message
Channel plugin '{self.name}' runtime '{self.runtime}' does not resolve to a BaseChannel subclass What it means
Import validation in load_channel_class: the PLUGIN.runtime 'module:attribute' target resolved, but the attribute is not a strict BaseChannel subclass (it is either missing, not a class, BaseChannel itself, or an unrelated type). This fires lazily — only when the channel class is actually needed — to keep manifest discovery dependency-free.
Solutions
- Fix the runtime target to point at the channel's BaseChannel subclass, e.g. 'nanobot.channels.<name>.runtime:MyChannel'
- Ensure the class inherits from nanobot.channels.base.BaseChannel
- Confirm the module imports without errors (missing optional SDKs surface here as resolution failure)
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at nanobot/channels/plugin.py:86 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/c206bc2bbe689ca9.
Report an issue: GitHub.
Appendix: source
Thrown at nanobot/channels/plugin.py:86
if self.webui is not None:
webui = self.webui.replace("\\", "/")
if webui.startswith("/") or ".." in webui.split("/"):
raise ValueError("channel plugin webui entry must stay inside its package")
object.__setattr__(self, "webui", webui)
def load_channel_class(self) -> type[BaseChannel]:
"""Resolve and validate the runtime class only when the channel is needed."""
from nanobot.channels.base import BaseChannel
module_name, _, attr_name = self.runtime.partition(":")
module = importlib.import_module(module_name)
channel_cls: Any = getattr(module, attr_name, None)
if (
not isinstance(channel_cls, type)
or not issubclass(channel_cls, BaseChannel)
or channel_cls is BaseChannel
):
raise ImportError(
f"Channel plugin '{self.name}' runtime '{self.runtime}' "
"does not resolve to a BaseChannel subclass"
)
if channel_cls.name != self.name:
raise ImportError(
f"Channel plugin '{self.name}' runtime declares name '{channel_cls.name}'"
)
return channel_cls
def load_connector(self) -> Any:
"""Construct the optional channel-owned interactive connector."""
if self.connector is None:
raise ImportError(f"Channel plugin '{self.name}' does not provide a connector")
module_name, attr_name = _target_parts(self.connector, label="connector")
module = importlib.import_module(module_name)
factory = getattr(module, attr_name, None)
if not callable(factory):
raise ImportError(View on GitHub (pinned to 42f37dc4c0)