langchain-ai/deepagents · error · TypeError
` ` entries must be strings, got ( )
Error message
`{field_name}` entries must be strings, got {type(entry).__name__} ({entry!r}) What it means
After confirming the container type, _coerce_frozen_strset checks each entry is a str. A non-string element raises a TypeError naming the field, the element's type, and its repr. This keeps excluded tool/middleware sets strictly string-based.
Solutions
- Cast each entry to str (or map enum members to their string names) before calling from_dict.
- Quote entries in YAML that could parse as non-strings (e.g. 'no', 'on', numeric-looking names).
- Filter or repair the list upstream so it contains only strings.
Example fix
// before
config = HarnessProfileConfig.from_dict({"excluded_tools": ["bash", 42]})
// after
config = HarnessProfileConfig.from_dict({"excluded_tools": [str(t) for t in ["bash", 42]]}) Defensive patterns
Strategy: type-guard
Validate before calling
tools = data.get("excluded_tools") or []
if not all(isinstance(e, str) for e in tools):
data["excluded_tools"] = [str(e) for e in tools] Type guard
def is_str_list(value: object) -> TypeGuard[list[str]]:
return isinstance(value, (list, tuple, set, frozenset)) and all(isinstance(e, str) for e in value) Try / catch
try:
config = HarnessProfileConfig.from_dict(data)
except TypeError as e:
if "entries must be strings" in str(e):
field = str(e).split('`')[1]
data[field] = [str(e2) for e2 in data[field]]
config = HarnessProfileConfig.from_dict(data)
else:
raise Prevention
- Map enum members to their string names before building exclusion lists.
- Quote YAML entries that could parse as booleans or numbers ('no', '1').
- Validate list element types at config-load boundaries.
When it happens
Trigger: from_dict receiving excluded_tools/excluded_middleware containing non-str items, e.g. {"excluded_tools": ["bash", 42]} or enums/None mixed into the list.
Common situations: Configs generated by scripts appending raw IDs or enum members instead of tool-name strings; YAML lists where an entry parsed as a number or boolean (e.g. a tool literally named `no` becoming False in YAML).
Related errors
- ` ` must be a list/set of strings, got
- context.auto_approve must be a boolean or null, got
- context.hooks_server_events must be a list of strings or…
- context. must be a string or null, got .
- context. must be an object, got .
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/d821b822ca81148b.
Report an issue: GitHub.
Appendix: source
Thrown at libs/deepagents/deepagents/profiles/harness/harness_profiles.py:854
if not isinstance(key, str) or not isinstance(val, str):
msg = f"`{field_name}` keys and values must be strings"
raise TypeError(msg)
out[key] = val
return out
def _coerce_frozen_strset(value: object, field_name: str) -> frozenset[str]:
"""Validate that `value` is an iterable of strings (or `None`)."""
if value is None:
return frozenset()
if not isinstance(value, (list, tuple, set, frozenset)):
msg = f"`{field_name}` must be a list/set of strings, got {type(value).__name__}"
raise TypeError(msg)
entries: list[str] = []
for entry in value:
if not isinstance(entry, str):
msg = f"`{field_name}` entries must be strings, got {type(entry).__name__} ({entry!r})"
raise TypeError(msg)
entries.append(entry)
return frozenset(entries)
def _coerce_general_purpose_subagent(value: object) -> GeneralPurposeSubagentProfile | None:
"""Validate and construct a `GeneralPurposeSubagentProfile` from a dict value."""
if value is None:
return None
if isinstance(value, Mapping):
return GeneralPurposeSubagentProfile.from_dict(cast("Mapping[str, Any]", value))
msg = f"`general_purpose_subagent` must be a mapping, got {type(value).__name__}"
raise TypeError(msg)
def _validate_config_middleware_string(entry: object, field_name: str) -> None:
"""Validate grammar of a string `excluded_middleware` entry.
Runs at `HarnessProfile` / `HarnessProfileConfig` construction so malformedView on GitHub (pinned to a1af029e6e)