{"record":{"id":"199f06665fc3e271","repo":"langchain-ai/deepagents","slug":"system-prompt-must-be-str-or-none-got-type-syste-199f06","errorCode":null,"errorMessage":"system_prompt must be str or None, got {type(system_prompt).__name__}","messagePattern":"system_prompt must be str or None, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"libs/deepagents/deepagents/middleware/skills.py","lineNumber":841,"sourceCode":"                are rendered as `**{label} Skills**` in the system prompt\n                (do not include the trailing `Skills` in your label).\n            system_prompt: System-prompt fragment template. Must contain\n                `{skills_locations}`, `{skills_load_warnings}`, and\n                `{skills_list}` slots for runtime substitution. Pass `None`\n                to skip appending entirely (skills are still loaded into\n                `state[\"skills_metadata\"]`).\n\n        Raises:\n            TypeError: If a tuple entry in `sources` is not exactly a\n                `(str, str)` pair, or if `system_prompt` is not `str` or\n                `None`.\n            ValueError: If `system_prompt` is a string missing any of the\n                required format slots.\n        \"\"\"\n        if system_prompt is not None:\n            if not isinstance(system_prompt, str):\n                msg = f\"system_prompt must be str or None, got {type(system_prompt).__name__}\"\n                raise TypeError(msg)\n            required = (\"{skills_locations}\", \"{skills_load_warnings}\", \"{skills_list}\")\n            missing = [slot for slot in required if slot not in system_prompt]\n            if missing:\n                msg = f\"system_prompt missing required format slot(s): {', '.join(missing)}\"\n                raise ValueError(msg)\n        self._backend = backend\n        # `self.sources` remains paths-only (`list[str]`) to preserve\n        # backwards-compat for callers that inspect it directly; label\n        # information is mirrored on `self.source_labels` at the same index.\n        self.sources: list[str] = [_source_path(s) for s in sources]\n        self.source_labels: list[str] = [_derive_source_label(s) for s in sources]\n        self.system_prompt_template = system_prompt\n\n    def _format_skills_locations(self) -> str:\n        \"\"\"Format skills locations for display in system prompt.\"\"\"\n        locations = []\n        last = len(self.sources) - 1\n","sourceCodeStart":823,"sourceCodeEnd":859,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/deepagents/deepagents/middleware/skills.py#L823-L859","documentation":"SkillsMiddleware accepts a custom `system_prompt` as a str or None; anything else (e.g. a list of prompt parts, a ChatPromptTemplate, bytes) is rejected with TypeError. String prompts are additionally checked for required format slots, so non-string composite prompt objects must be converted to a str first.","triggerScenarios":"SkillsMiddleware(backend=..., system_prompt=[\"part1\", \"part2\"]) or passing a LangChain prompt template / ChatPromptTemplate object instead of a rendered string.","commonSituations":"Building the prompt programmatically as a list and forgetting to join; passing an f-string pipeline object; refactoring from another middleware that accepted templates.","solutions":["Convert to str: system_prompt=\"\\n\".join(parts) or str(template.invoke({})).","Pass None to use the default system prompt.","If composing dynamically, render the final template into a string before constructing.","Use only the three supported slots {skills_locations}, {skills_load_warnings}, {skills_list} when customizing."],"exampleFix":"// before\nsystem_prompt=[intro, instructions]\n// after\nsystem_prompt=\"\\n\\n\".join([intro, instructions])","handlingStrategy":"type-guard","validationCode":"sp = system_prompt\nif sp is not None and not isinstance(sp, str):\n    sp = \"\\n\".join(sp) if isinstance(sp, list) else str(sp)","typeGuard":"def is_valid_system_prompt(v: object) -> TypeGuard[str | None]:\n    return v is None or isinstance(v, str)","tryCatchPattern":"try:\n    mw = SkillsMiddleware(backend=b, system_prompt=system_prompt)\nexcept TypeError as e:\n    if \"system_prompt must be str or None\" in str(e):\n        mw = SkillsMiddleware(backend=b, system_prompt=str(system_prompt))\n    else:\n        raise","preventionTips":["Render templates/lists to a single str before passing.","Pass None to use the built-in default prompt.","Type-annotate system_prompt: str | None at call sites.","Don't pass LangChain prompt objects directly to the middleware."],"tags":["python","skills","validation","type-error"],"backgroundTag":"invalid-parameter-type","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}