bytedance/deer-flow · warning · HTTPException
Unknown channel provider
Error message
Unknown channel provider
What it means
404 from _provider_config (channel_connections.py:216): the requested provider name is not a key in _PROVIDER_META (the router's allowlist of known channel providers: telegram, slack, discord, feishu, dingtalk, wechat, wecom, buzz). The allowlist exists deliberately — an unrestricted getattr would let a request-supplied name matching a non-provider config attribute (like 'enabled' or 'require_bound_identity') slip past the 404 and be dereferenced as a provider config, causing a 500.
Source
Thrown at backend/app/gateway/routers/channel_connections.py:216
return repo
sf = get_session_factory()
if sf is None:
raise HTTPException(status_code=503, detail="Channel connection persistence is not available")
repo = ChannelConnectionRepository(sf)
request.app.state.channel_connection_repo = repo
return repo
def _provider_config(config: ChannelConnectionsConfig, provider: str):
# Resolve provider configs only for known providers. An unrestricted
# getattr would let a request-supplied name that happens to match another
# config attribute (e.g. the "enabled" / "require_bound_identity" bool
# fields) slip past the 404 and return a non-provider value, which callers
# then dereference as a provider config (AttributeError -> HTTP 500).
if provider not in _PROVIDER_META:
raise HTTPException(status_code=404, detail="Unknown channel provider")
provider_config = getattr(config, provider, None)
if provider_config is None:
raise HTTPException(status_code=404, detail="Unknown channel provider")
return provider_config
def _runtime_channel_configured(provider: str, channels_config: dict[str, Any]) -> bool:
runtime_config = channels_config.get(provider)
if not isinstance(runtime_config, dict) or not runtime_config.get("enabled", False):
return False
return all(str(runtime_config.get(key) or "").strip() for key in _RUNTIME_REQUIREMENTS[provider])
def _runtime_unavailable_reason(provider: str) -> str:
meta = _PROVIDER_META.get(provider)
display_name = meta["display_name"] if meta else provider
return f"Enter the required {display_name} credentials to connect this channel."
View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Use one of the supported provider slugs exactly: telegram, slack, discord, feishu, dingtalk, wechat, wecom, buzz
- Fetch the provider list from the API's discovery/metadata endpoint (or _PROVIDER_META-backed listing) instead of hardcoding, so version drift cannot produce unknown names
- Upgrade the backend if you need a provider added in a newer release
Example fix
# before curl /api/channels/connections/whatsapp/connect -X POST # -> 404 Unknown channel provider # after curl /api/channels/connections/feishu/connect -X POST
Defensive patterns
Strategy: type-guard
Validate before calling
const SUPPORTED = new Set(["telegram","slack","discord","feishu","dingtalk","wechat","wecom","buzz"]);
if (!SUPPORTED.has(provider)) throw new Error(`Unsupported provider: ${provider}`); Type guard
const CHANNEL_PROVIDERS = ["telegram","slack","discord","feishu","dingtalk","wechat","wecom","buzz"] as const; type ChannelProvider = typeof CHANNEL_PROVIDERS[number]; const isChannelProvider = (p: string): p is ChannelProvider => (CHANNEL_PROVIDERS as readonly string[]).includes(p);
Try / catch
try { await connectProvider(provider) } catch (e) { if (e.status === 404 && e.detail === "Unknown channel provider") filterProviderFromUI(provider); else throw e; } Prevention
- Drive provider lists from the API's own metadata endpoint instead of hardcoding
- Keep the client's provider list in lockstep with the deployed backend version
- Never probe with config-attribute-like names — the allowlist 404 is intentional hardening
When it happens
Trigger: Calling /api/channels/connections/{provider}/... with a provider not in the fixed set — e.g. 'whatsapp', 'email', 'ENABLED', or any typo like 'slackk'.
Common situations: Client written against docs listing providers the backend version doesn't support (provider set differs across DeerFlow versions); automated client iterating a hardcoded provider list that includes unsupported names; probing the endpoint with config-attribute names.
Related errors
- Channel session assistant_id is empty. Use 'lead_agent' or a
- Invalid channel session assistant_id {raw_value!r}. Use 'lea
- Invalid provider ID
- Failed to load agents: ${res.statusText}
- Agent '${name}' not found
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/ff5504e5fa73771f.
Report an issue: GitHub.