{"record":{"id":"52d9eb733fdcc2dd","repo":"huggingface/transformers","slug":"provided-path-save-directory-should-be-a-direc-52d9eb","errorCode":null,"errorMessage":"Provided path ({save_directory}) should be a directory, not a file","messagePattern":"Provided path \\((.+?)\\) should be a directory, not a file","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"src/transformers/feature_extraction_utils.py","lineNumber":399,"sourceCode":"        return cls.from_dict(feature_extractor_dict, **kwargs)\n\n    def save_pretrained(self, save_directory: str | os.PathLike, push_to_hub: bool = False, **kwargs):\n        \"\"\"\n        Save a feature_extractor object to the directory `save_directory`, so that it can be re-loaded using the\n        [`~feature_extraction_utils.FeatureExtractionMixin.from_pretrained`] class method.\n\n        Args:\n            save_directory (`str` or `os.PathLike`):\n                Directory where the feature extractor JSON file will be saved (will be created if it does not exist).\n            push_to_hub (`bool`, *optional*, defaults to `False`):\n                Whether or not to push your model to the Hugging Face model hub after saving it. You can specify the\n                repository you want to push to with `repo_id` (will default to the name of `save_directory` in your\n                namespace).\n            kwargs (`dict[str, Any]`, *optional*):\n                Additional key word arguments passed along to the [`~utils.PushToHubMixin.push_to_hub`] method.\n        \"\"\"\n        if os.path.isfile(save_directory):\n            raise AssertionError(f\"Provided path ({save_directory}) should be a directory, not a file\")\n\n        os.makedirs(save_directory, exist_ok=True)\n\n        if push_to_hub:\n            commit_message = kwargs.pop(\"commit_message\", None)\n            repo_id = kwargs.pop(\"repo_id\", save_directory.split(os.path.sep)[-1])\n            repo_id = hf_api().create_repo(repo_id, exist_ok=True, **kwargs).repo_id\n            files_timestamps = self._get_files_timestamps(save_directory)\n\n        # If we have a custom config, we copy the file defining it in the folder and set the attributes so it can be\n        # loaded from the Hub.\n        if self._auto_class is not None:\n            custom_object_save(self, save_directory, config=self)\n\n        # If we save using the predefined names, we can load using `from_pretrained`\n        output_feature_extractor_file = os.path.join(save_directory, FEATURE_EXTRACTOR_NAME)\n\n        self.to_json_file(output_feature_extractor_file)","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/huggingface/transformers/blob/a597f974857b3d92939971296bc0deb93d33d780/src/transformers/feature_extraction_utils.py#L381-L417","documentation":"FeatureExtractorBase.save_pretrained expects a directory to write preprocessor_config.json into. If save_directory points at an existing file, writing would clobber it, so os.path.isfile triggers an immediate AssertionError before makedirs.","triggerScenarios":"Calling fe.save_pretrained(path) where path is a file — commonly passing the intended JSON filename itself (e.g. 'config.json') instead of its parent folder, or a path created by an earlier file write.","commonSituations":"Confusion between 'save to this file' vs 'save into this directory' APIs; scripts that create the target path as a file first; typos where the filename is used as the directory.","solutions":["Pass the directory: fe.save_pretrained('./my-extractor') — the JSON filename is chosen automatically","If the path exists as a file by mistake, remove/rename it first","To control the filename, save into a directory and rename the emitted preprocessor_config.json afterwards"],"exampleFix":"# before\nfe.save_pretrained(\"checkpoints/preprocessor_config.json\")\n\n# after\nfe.save_pretrained(\"checkpoints\")","handlingStrategy":"validation","validationCode":"import os\n\ndef ensure_dir(path):\n    if os.path.isfile(path):\n        raise ValueError(f\"{path} is a file; pass its parent directory\")\n    os.makedirs(path, exist_ok=True)\n    return path","typeGuard":"def is_directory_path(path) -> bool:\n    import os\n    return not os.path.isfile(path)","tryCatchPattern":"try:\n    fe.save_pretrained(path)\nexcept AssertionError as e:\n    if \"should be a directory\" in str(e):\n        import os\n        fe.save_pretrained(os.path.dirname(path))\n    else:\n        raise","preventionTips":["Pass folders, never filenames, to save_pretrained","Create and verify the output directory before saving","Standardize on one helper for all save paths in the pipeline"],"tags":["feature-extractor","save","filesystem","transformers"],"backgroundTag":null,"analyzedSha":"a597f974857b3d92939971296bc0deb93d33d780","analyzedAt":"2026-08-14T18:24:08.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}