langchain-ai/deepagents · error · ValueError

invalid {provider} exposure mode {value!r}; expected one of:

Error message

invalid {provider} exposure mode {value!r}; expected one of: {modes}

What it means

`_exposure_mode` converts the exposure env string into an `ExposureMode` via `ExposureMode(value)`; valid values are `self`, `allowlist`, and `open`. An unknown string raises a ValueError listing the provider name, the bad value, and all accepted modes.

Source

Thrown at libs/talon/deepagents_talon/channels/base.py:456


def _is_self_message(message: ChannelMessage, operator_ids: frozenset[str]) -> bool:
    if message.metadata.get("from_self") is True:
        return True
    return message.sender_id is not None and message.sender_id in operator_ids


def _matches_text(text: str, patterns: tuple[str, ...]) -> bool:
    return any(fnmatch.fnmatchcase(text, pattern) for pattern in patterns)


def _exposure_mode(value: str, *, provider: str) -> ExposureMode:
    try:
        return ExposureMode(value)
    except ValueError as error:
        modes = ", ".join(mode.value for mode in ExposureMode)
        msg = f"invalid {provider} exposure mode {value!r}; expected one of: {modes}"
        raise ValueError(msg) from error


def _require_open_acknowledgement(
    env: Mapping[str, str],
    config: ChannelExposureEnv,
) -> None:
    if env.get(config.open_ack) == config.open_ack_value:
        return
    msg = (
        f"{config.provider} exposure mode 'open' allows arbitrary senders to trigger the "
        "agent with operator credentials and local host access; set "
        f"{config.open_ack}={config.open_ack_value} to acknowledge this risk"
    )
    raise ValueError(msg)


def _split_index(text: str, limit: int) -> int:
    window = text[:limit]

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Set the var to one of the listed modes exactly: `self`, `allowlist`, or `open`.
  2. Use lowercase values; the enum is case-sensitive.
  3. Catch the ValueError at startup — the message enumerates valid modes for the given provider.

Example fix

# before
DEEPAGENTS_TALON_TELEGRAM_EXPOSURE=whitelist

# after
DEEPAGENTS_TALON_TELEGRAM_EXPOSURE=allowlist
Defensive patterns

Strategy: validation

Validate before calling

import os
valid = {'self', 'allowlist', 'open'}
raw = os.environ.get('DEEPAGENTS_TALON_TELEGRAM_EXPOSURE', 'self')
if raw not in valid:
    raise SystemExit(f'{raw!r} is not a valid exposure mode; expected one of: ' + ', '.join(sorted(valid)))

Try / catch

try:
    exposure = channel_exposure_from_env(os.environ, config)
except ValueError as exc:
    raise SystemExit(f'invalid exposure config: {exc}') from exc

Prevention

When it happens

Trigger: Setting `<PREFIX>_EXPOSURE` (e.g. `DEEPAGENTS_TALON_TELEGRAM_EXPOSURE`) to anything other than `self`/`allowlist`/`open` — e.g. `public`, `whitelist`, `Open` (case matters beyond exact match), `restricted` — then calling `channel_exposure_from_env` from `from_talon_config`.

Common situations: Typo'd or older mode names from previous versions (`whitelist` vs `allowlist`); capitalized values from YAML-exported env; copying config between providers with different modes.

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/5015854e8d6ab195. Report an issue: GitHub.