langchain-ai/deepagents · error · TypeError
`{field_name}` must be str or None, got {type(value).__name_
Error message
`{field_name}` must be str or None, got {type(value).__name__} What it means
_coerce_str_or_none validates fields loaded from a dict via HarnessProfileConfig.from_dict. If a value for a string-typed field (e.g. base_system_prompt, system_prompt_suffix) is neither None nor str, a TypeError is raised naming the field and the actual type. This enforces the declared schema on deserialized configs.
Source
Thrown at libs/deepagents/deepagents/profiles/harness/harness_profiles.py:824
Derived from `HarnessProfileConfig`'s dataclass fields so the set stays in
sync automatically. Runtime-only fields such as `extra_middleware` are
absent because they don't exist on `HarnessProfileConfig`.
"""
_GENERAL_PURPOSE_SUBAGENT_KEYS: frozenset[str] = frozenset(f.name for f in fields(GeneralPurposeSubagentProfile))
"""Keys accepted by `GeneralPurposeSubagentProfile.from_dict`.
Derived from the dataclass fields for drift-free parity with the class.
"""
def _coerce_str_or_none(value: object, field_name: str) -> str | None:
"""Validate that `value` is a string or `None` for dict-loaded string fields."""
if value is None or isinstance(value, str):
return value
msg = f"`{field_name}` must be str or None, got {type(value).__name__}"
raise TypeError(msg)
def _coerce_str_mapping(value: object, field_name: str) -> dict[str, str]:
"""Validate that `value` is a `str -> str` mapping (or `None`) and return a plain dict."""
if value is None:
return {}
if not isinstance(value, Mapping):
msg = f"`{field_name}` must be a mapping, got {type(value).__name__}"
raise TypeError(msg)
out: dict[str, str] = {}
for key, val in value.items():
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
View on GitHub (pinned to a1af029e6e)
Solutions
- Convert the value to a string before calling from_dict (e.g. str(value) or join list chunks).
- Omit the key or pass None if the field should be unset.
- Fix the source config file so the field is a quoted string.
Example fix
// before
config = HarnessProfileConfig.from_dict({"base_system_prompt": ["line1", "line2"]})
// after
config = HarnessProfileConfig.from_dict({"base_system_prompt": "\n".join(["line1", "line2"])}) Defensive patterns
Strategy: type-guard
Validate before calling
value = data.get("base_system_prompt")
if value is not None and not isinstance(value, str):
value = "\n".join(value) if isinstance(value, list) else str(value) Type guard
def is_str_or_none(value: object) -> TypeGuard[str | None]:
return value is None or isinstance(value, str) Try / catch
try:
config = HarnessProfileConfig.from_dict(data)
except TypeError as e:
if "must be str or None" in str(e):
field = str(e).split('`')[1]
data[field] = str(data[field])
config = HarnessProfileConfig.from_dict(data)
else:
raise Prevention
- Ensure prompt fields in YAML/JSON are quoted strings, not lists or numbers.
- Normalize config input (cast/join) before from_dict.
- Add a schema check on config files at load time.
When it happens
Trigger: Calling HarnessProfileConfig.from_dict with e.g. {"base_system_prompt": 123} or {"system_prompt_suffix": ["part1"]} — any non-str, non-None value for a string field.
Common situations: JSON/YAML configs where a prompt field was given as a list of prompt chunks or a number; template variables left as placeholders of the wrong type; programmatic config builders assigning non-string values.
Related errors
- `general_purpose_subagent` must be a mapping, got {type(valu
- interpreter_ptc must be False, 'safe', 'all', or a list of t
- max_retries must be an int, got {type(max_retries).__name__}
- stream_output_is_visible must be a bool, got {type(stream_ou
- context.{key} must be a string or null, got {type(value).__n
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/e72b41c6b73e02dc.
Report an issue: GitHub.