PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Writer\Exception

Could not close file after writing.

Error message

Could not close file after writing.

What it means

After writing, maybeCloseFileHandle() calls fclose() on handles the writer opened itself (shouldCloseFile). fclose returns false when pending buffers cannot be flushed, typically disk full, quota exceeded, or network storage dropping mid-write, and the writer converts that into 'Could not close file after writing.' Any file that hits this should be treated as incomplete or corrupt.

Source

Thrown at src/PhpSpreadsheet/Writer/BaseWriter.php:138

        }

        $this->fileHandle = $fileHandle;
        $this->shouldCloseFile = true;
    }

    protected function tryClose(): bool
    {
        return fclose($this->fileHandle);
    }

    /**
     * Close file handle only if we opened it ourselves.
     */
    protected function maybeCloseFileHandle(): void
    {
        if ($this->shouldCloseFile) {
            if (!$this->tryClose()) {
                throw new Exception('Could not close file after writing.');
            }
        }
    }
}

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Free space or raise the quota, then regenerate the export; do not ship the partial file.
  2. Pre-check with disk_free_space(dirname($path)) against a rough size estimate before saving.
  3. Write to local temp storage first, then copy the finished file to network destinations.
  4. Prune old exports in batch jobs so the volume stays below capacity.

Example fix

// before
$writer->save('/mnt/nfs/exports/report.xlsx'); // storage fills or drops mid-write

// after
$tmp = tempnam(sys_get_temp_dir(), 'xlsx');
$writer->save($tmp); // local disk first
copy($tmp, '/mnt/nfs/exports/report.xlsx');
unlink($tmp);
Defensive patterns

Strategy: try-catch

Validate before calling

$needed = 100 * 1024 * 1024; // rough upper bound for the export
$free = disk_free_space(dirname($path));
if ($free === false || $free < $needed) {
    throw new RuntimeException('Insufficient disk space for export');
}
$writer->save($path);

Try / catch

use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;

try {
    $writer->save($path);
} catch (WriterException $e) {
    if (str_contains($e->getMessage(), 'Could not close file')) {
        unlink($path); // discard the partial, corrupt output
        // alert the operator: disk full or storage dropped mid-write
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: save() onto a filesystem that fills up during the write; hosting quota exceeded partway through a large export; NFS/SMB share disconnecting before the final flush.

Common situations: Containers with small ephemeral disks; shared hosting with file quotas; batch jobs that accumulate exports until the volume is full; very large spreadsheets whose final flush exceeds remaining space.

Related errors


AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17). Data as JSON: /api/errors/5eadca7af71a4385. Report an issue: GitHub.