Lightning-AI/pytorch-lightning · error · IsADirectoryError

The checkpoint path exists and is a directory: {path}

Error message

The checkpoint path exists and is a directory: {path}

What it means

When saving a checkpoint with ModelParallelStrategy without distributed checkpointing (_save_distributed_checkpoint=False), the target path must be a file. If the resolved path already exists as a directory (and is not recognized as a sharded checkpoint being resumed), Lightning raises IsADirectoryError.

Source

Thrown at src/lightning/pytorch/strategies/model_parallel.py:313

    @override
    def load_optimizer_state_dict(self, checkpoint: Mapping[str, Any]) -> None:
        # Override to do nothing, the strategy already loaded the states in `load_checkpoint()`
        pass

    @override
    def save_checkpoint(
        self, checkpoint: dict[str, Any], filepath: _PATH, storage_options: Optional[Any] = None
    ) -> None:
        if storage_options is not None:
            raise TypeError(
                f"`{type(self).__name__}.save_checkpoint(..., storage_options=...)` is not supported because"
                f" `{type(self).__name__}` does not use the `CheckpointIO`."
            )
        # broadcast the path from rank 0 to ensure all the checkpoints are saved to a common path
        path = _resolve_path(self.broadcast(filepath))
        if _is_checkpoint_dir(path) and not self._save_distributed_checkpoint and not _is_sharded_checkpoint(path):
            raise IsADirectoryError(f"The checkpoint path exists and is a directory: {path}")

        if self._save_distributed_checkpoint:
            _prepare_directory_checkpoint(path)

            converted_state = {"state_dict": checkpoint.pop("state_dict")}
            converted_state.update({
                f"optimizer_{idx}": optim_state
                for idx, optim_state in enumerate(checkpoint.pop("optimizer_states", []))
            })
            _distributed_checkpoint_save(converted_state, path)

            if self.global_rank == 0:
                _atomic_save(checkpoint, _checkpoint_join(path, _METADATA_FILENAME))
        else:
            if _is_sharded_checkpoint(path):
                _remove_checkpoint(path)
            return super().save_checkpoint(checkpoint=checkpoint, filepath=path)

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Pass a full file path, e.g. os.path.join(dirpath, 'last.ckpt')
  2. If the target really should be a sharded/distributed checkpoint directory, enable the strategy's distributed checkpoint option (_save_distributed_checkpoint=True)
  3. Remove or rename the conflicting directory if it was created by mistake

Example fix

# before
strategy.save_checkpoint(ckpt, "checkpoints/run1/")

# after
strategy.save_checkpoint(ckpt, "checkpoints/run1/last.ckpt")
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
p = Path(filepath)
assert not (p.exists() and p.is_dir()), f"{filepath} is a directory; pass a file path like {p}/last.ckpt"

Prevention

When it happens

Trigger: Calling save_checkpoint with a path that is an existing directory (e.g. passing a run dir like 'checkpoints/run1/' rather than 'checkpoints/run1/last.ckpt'), while not using distributed checkpoints and the dir not being a sharded checkpoint.

Common situations: Passing ModelCheckpoint.dirpath instead of a filename; reusing a resume path that points at a DCP directory while the strategy is in full-checkpoint mode.

Related errors


AI-assisted analysis of Lightning-AI/pytorch-lightning@9fed5c27d2 (2026-08-28). Data as JSON: /api/errors/aae2711626dd4e86. Report an issue: GitHub.