{"record":{"id":"24033ecad95ea039","repo":"langchain-ai/langchain","slug":"save-path-must-be-json-or-yaml","errorCode":null,"errorMessage":"{save_path} must be json or yaml","messagePattern":"(.+?) must be json or yaml","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/language_models/llms.py","lineNumber":1439,"sourceCode":"        \"\"\"\n        # Convert file to Path object.\n        save_path = Path(file_path)\n\n        directory_path = save_path.parent\n        directory_path.mkdir(parents=True, exist_ok=True)\n\n        # Fetch dictionary to save\n        prompt_dict = self._dict_for_compat()\n\n        if save_path.suffix == \".json\":\n            with save_path.open(\"w\", encoding=\"utf-8\") as f:\n                json.dump(prompt_dict, f, indent=4)\n        elif save_path.suffix.endswith((\".yaml\", \".yml\")):\n            with save_path.open(\"w\", encoding=\"utf-8\") as f:\n                yaml.dump(prompt_dict, f, default_flow_style=False)\n        else:\n            msg = f\"{save_path} must be json or yaml\"\n            raise ValueError(msg)\n\n\nclass LLM(BaseLLM):\n    \"\"\"Simple interface for implementing a custom LLM.\n\n    You should subclass this class and implement the following:\n\n    - `_call` method: Run the LLM on the given prompt and input (used by `invoke`).\n    - `_identifying_params` property: Return a dictionary of the identifying parameters\n        This is critical for caching and tracing purposes. Identifying parameters\n        is a dict that identifies the LLM.\n        It should mostly include a `model_name`.\n\n    Optional: Override the following methods to provide more optimizations:\n\n    - `_acall`: Provide a native async version of the `_call` method.\n        If not provided, will delegate to the synchronous version using\n        `run_in_executor`. (Used by `ainvoke`).","sourceCodeStart":1421,"sourceCodeEnd":1457,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/language_models/llms.py#L1421-L1457","documentation":"Raised by BaseLLM.save_to_disk (via save) when the target file's suffix is neither .json nor .yaml/.yml. The LLM configuration is serialized by inspecting the path extension, so any other extension is unsupported.","triggerScenarios":"llm.save_to_disk(Path('model.cfg')), llm.save_to_disk('llm.txt'), or a path with no suffix. Only '.json', '.yaml', and '.yml' are accepted (checked on save_path.suffix, so '.yml' works via the endswith check).","commonSituations":"Using a generic config filename like model.conf or llm.pkl; case-sensitivity surprises like '.JSON' (suffix comparison is case-sensitive); building paths dynamically without normalizing the extension.","solutions":["Rename the target file to end in .json (recommended, avoids the optional PyYAML dependency): e.g. Path('model.json')","Or use .yaml / .yml if YAML output is preferred","Normalize the suffix before saving: save_path = save_path.with_suffix('.json')"],"exampleFix":"# before\nllm.save_to_disk(Path('model_config.cfg'))\n# after\nllm.save_to_disk(Path('model_config.json'))","handlingStrategy":"validation","validationCode":"from pathlib import Path\np = Path(save_path)\nif p.suffix not in {'.json', '.yaml', '.yml'}:\n    p = p.with_suffix('.json')\nllm.save(p)","typeGuard":"def is_supported_save_path(p: 'Path') -> bool:\n    return p.suffix in {'.json', '.yaml', '.yml'}","tryCatchPattern":"try:\n    llm.save(save_path)\nexcept ValueError as e:\n    if 'must be json or yaml' in str(e):\n        llm.save(save_path.with_suffix('.json'))\n    else:\n        raise","preventionTips":["Normalize the extension before saving: path.with_suffix('.json')","Extensions are compared case-sensitively — use lowercase .json/.yaml/.yml","Prefer .json to avoid requiring PyYAML at load time"],"tags":["llm","persistence","serialization","file-io"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}