{"record":{"id":"f328c154dda104e5","repo":"langchain-ai/deepagents","slug":"field-name-keys-and-values-must-be-strings","errorCode":null,"errorMessage":"`{field_name}` keys and values must be strings","messagePattern":"`(.+?)` keys and values must be strings","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"libs/deepagents/deepagents/profiles/harness/harness_profiles.py","lineNumber":838,"sourceCode":"    \"\"\"Validate that `value` is a string or `None` for dict-loaded string fields.\"\"\"\n    if value is None or isinstance(value, str):\n        return value\n    msg = f\"`{field_name}` must be str or None, got {type(value).__name__}\"\n    raise TypeError(msg)\n\n\ndef _coerce_str_mapping(value: object, field_name: str) -> dict[str, str]:\n    \"\"\"Validate that `value` is a `str -> str` mapping (or `None`) and return a plain dict.\"\"\"\n    if value is None:\n        return {}\n    if not isinstance(value, Mapping):\n        msg = f\"`{field_name}` must be a mapping, got {type(value).__name__}\"\n        raise TypeError(msg)\n    out: dict[str, str] = {}\n    for key, val in value.items():\n        if not isinstance(key, str) or not isinstance(val, str):\n            msg = f\"`{field_name}` keys and values must be strings\"\n            raise TypeError(msg)\n        out[key] = val\n    return out\n\n\ndef _coerce_frozen_strset(value: object, field_name: str) -> frozenset[str]:\n    \"\"\"Validate that `value` is an iterable of strings (or `None`).\"\"\"\n    if value is None:\n        return frozenset()\n    if not isinstance(value, (list, tuple, set, frozenset)):\n        msg = f\"`{field_name}` must be a list/set of strings, got {type(value).__name__}\"\n        raise TypeError(msg)\n    entries: list[str] = []\n    for entry in value:\n        if not isinstance(entry, str):\n            msg = f\"`{field_name}` entries must be strings, got {type(entry).__name__} ({entry!r})\"\n            raise TypeError(msg)\n        entries.append(entry)\n    return frozenset(entries)","sourceCodeStart":820,"sourceCodeEnd":856,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/deepagents/deepagents/profiles/harness/harness_profiles.py#L820-L856","documentation":"After confirming the value is a Mapping, _coerce_str_mapping checks that every key and value is a str. Any non-string key or value raises a TypeError naming the field. This keeps tool-description override tables strictly str->str.","triggerScenarios":"from_dict/to_dict/from_harness_profile receiving tool_description_overrides like {\"bash\": 42} (non-str value) or {42: \"desc\"} (non-str key), e.g. from JSON with numeric keys or enums as keys.","commonSituations":"JSON object keys serialized from numeric tool IDs; YAML configs where a description was written as a number or boolean; programmatic overrides built with enum or non-str tool names.","solutions":["Cast keys and values to str before passing them (str(key), str(value)).","Fix the source data so override entries are string-to-string.","Reject/repair the config upstream if keys are enums or ints, mapping them to official tool-name strings."],"exampleFix":"// before\noverrides = {ToolName.BASH: \"Run shell\"}\nconfig = HarnessProfileConfig.from_dict({\"tool_description_overrides\": overrides})\n// after\noverrides = {str(ToolName.BASH.value): \"Run shell\"}\nconfig = HarnessProfileConfig.from_dict({\"tool_description_overrides\": overrides})","handlingStrategy":"type-guard","validationCode":"overrides = data.get(\"tool_description_overrides\") or {}\nif not all(isinstance(k, str) and isinstance(v, str) for k, v in overrides.items()):\n    data[\"tool_description_overrides\"] = {str(k): str(v) for k, v in overrides.items()}","typeGuard":"def is_str_mapping(value: object) -> TypeGuard[dict[str, str]]:\n    return isinstance(value, Mapping) and all(\n        isinstance(k, str) and isinstance(v, str) for k, v in value.items()\n    )","tryCatchPattern":"try:\n    config = HarnessProfileConfig.from_dict(data)\nexcept TypeError as e:\n    if \"keys and values must be strings\" in str(e):\n        field = str(e).split('`')[1]\n        data[field] = {str(k): str(v) for k, v in data[field].items()}\n        config = HarnessProfileConfig.from_dict(data)\n    else:\n        raise","preventionTips":["Use official tool-name strings (not enums or ints) as override keys.","Quote numeric-looking keys in YAML/JSON configs.","Validate override tables with is_str_mapping at config load boundaries."],"tags":["python","type-error","validation","mapping"],"backgroundTag":"type-validation-failed","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}