HKUDS/nanobot · error · ValueError
channel plugin webui entry must stay inside its package
Error message
channel plugin webui entry must stay inside its package
What it means
Path-safety validation in ChannelPlugin.__post_init__: the webui entry, after normalizing backslashes to forward slashes, is absolute (leading '/') or contains '..' path segments, so it would escape the channel plugin's package directory. The guard keeps the WebUI entry file inside the plugin package.
Solutions
- Use a relative path within the channel package, e.g. 'webui/index.html'
- Remove leading slashes and any '..' segments from the webui entry
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at nanobot/channels/plugin.py:71 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/1b6907657052629f.
Report an issue: GitHub.
Appendix: source
Thrown at nanobot/channels/plugin.py:71
raise TypeError("channel plugin setup must be a ChannelSetupSpec or None")
if not isinstance(cast(object, self.management), ChannelManagementSpec):
raise TypeError("channel plugin management must be a ChannelManagementSpec")
if not isinstance(cast(object, self.dependencies), tuple) or not all(
isinstance(cast(object, requirement), str) and requirement.strip()
for requirement in self.dependencies
):
raise TypeError("channel plugin dependencies must be a tuple of requirements")
for dependency in self.dependencies:
try:
Requirement(dependency)
except InvalidRequirement as exc:
raise ValueError(
f"channel plugin dependency is not a valid requirement: {dependency}"
) from exc
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"
)View on GitHub (pinned to 42f37dc4c0)