langchain-ai/deepagents · error · ValueError
shell_allow_list must be None or non-empty
Error message
shell_allow_list must be None or non-empty
What it means
`ServerConfig.__post_init__` enforces that `shell_allow_list` is either `None` (meaning unrestricted/default behavior) or a non-empty list of shell commands. An explicitly provided empty list `[]` is ambiguous and therefore rejected with this `ValueError` at construction time.
Source
Thrown at libs/code/deepagents_code/_server_config.py:483
values.pop("PROJECT_ROOT")
serialized = json.dumps(values, sort_keys=True, separators=(",", ":"))
return hashlib.sha256(serialized.encode()).hexdigest()
def __post_init__(self) -> None:
"""Normalize fields and validate invariants.
Raises:
TypeError: If `rubric_max_iterations` or `recursion_limit` is a
boolean.
ValueError: If `shell_allow_list` is an empty list,
`allow_fs_tools` is an empty list or omits `"read_file"`, or
`rubric_max_iterations` / `recursion_limit` is non-positive.
"""
if self.sandbox_type == "none":
object.__setattr__(self, "sandbox_type", None)
if self.shell_allow_list is not None and len(self.shell_allow_list) == 0:
msg = "shell_allow_list must be None or non-empty"
raise ValueError(msg)
# `allow_fs_tools` is a security control: `None` means unrestricted, but
# an explicit list must be a usable allowlist. Own the non-empty +
# `read_file`-required invariant here (the single authoritative point
# for both the env round-trip via `from_env` and direct construction)
# rather than deferring to `FilesystemMiddleware`, which would only
# surface the violation a process boundary away. `_parse_allow_fs_tools_flag`
# still enforces the same rule at the CLI for a friendlier error.
if self.allow_fs_tools is not None:
if len(self.allow_fs_tools) == 0:
msg = "allow_fs_tools must be None or a non-empty list"
raise ValueError(msg)
if "read_file" not in self.allow_fs_tools:
msg = "allow_fs_tools must include 'read_file'"
raise ValueError(msg)
if isinstance(self.rubric_max_iterations, bool):
msg = "rubric_max_iterations must be None or a positive integer"
raise TypeError(msg)
if self.rubric_max_iterations is not None and self.rubric_max_iterations <= 0:View on GitHub (pinned to a1af029e6e)
Solutions
- Pass `shell_allow_list=None` if you intend unrestricted/default shell behavior
- Populate the list with at least one allowed command, e.g. shell_allow_list=["ls","grep"]
- Fix upstream code so a fully-filtered list collapses to `None` instead of `[]`
- If the value comes from the environment, unset `DEEPAGENTS_CODE_SERVER_SHELL_ALLOW_LIST` rather than setting it empty
Example fix
// before config = ServerConfig(shell_allow_list=[], ...) # ValueError: shell_allow_list must be None or non-empty // after config = ServerConfig(shell_allow_list=None, ...) # or ["ls", "cat"]
Defensive patterns
Strategy: validation
Validate before calling
def coerce_shell_allow_list(cmds: list[str] | None) -> list[str] | None:
return cmds if cmds else None # empty list collapses to None before constructing ServerConfig Type guard
def is_valid_shell_allow_list(value: object) -> bool:
return value is None or (isinstance(value, list) and len(value) > 0 and all(isinstance(c, str) for c in value)) Try / catch
try:
config = ServerConfig(**kwargs)
except ValueError as e:
if "shell_allow_list" in str(e):
print(f"Invalid shell_allow_list: {e}; pass None or a non-empty list")
sys.exit(2)
raise Prevention
- Normalize empty lists to None at the boundary where config values are built
- Never set list-valued env vars to empty values; unset them instead
- Add a unit test that constructs ServerConfig with your real config-loading path
- Filter-then-collapse pattern: after filtering a default list, substitute None if the result is empty
When it happens
Trigger: Constructing `ServerConfig` (directly or via `from_env`/`from_cli_args`) with `shell_allow_list=[]`, or setting `DEEPAGENTS_CODE_SERVER_SHELL_ALLOW_LIST` such that it round-trips to an empty list.
Common situations: Code that starts with a default list, filters it, and ends up empty before passing it in; env/CLI parsing that produces `[]` from an empty or blank value; template configs rendering an empty placeholder.
Related errors
- Invalid {SERVER_ENV_PREFIX}ALLOW_FS_TOOLS value: unknown fil
- Invalid interpreter_ptc string {ptc!r}; expected 'safe', 'al
- interpreter_ptc list entries cannot include 'all'; use 'all'
- Could not parse embedded resource block. Block expected eith
- question text must not be blank
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/f18f48065c0c4ded.
Report an issue: GitHub.