PHPOffice/PHPWord · warning · PhpOffice\PhpWord\Exception\Exception

The file could not be deleted.

Error message

The file {tempFileName} could not be deleted.

What it means

XMLWriter using file storage creates a temporary file; __destruct() unlinks it when the object is garbage collected. If unlink() fails on non-Windows systems, Exception('The file ... could not be deleted.') is thrown from the destructor — a notoriously awkward place for an exception, often surfacing as an uncatchable-looking error during shutdown.

Solutions

  1. Ensure the temp directory (from sys_get_temp_dir() or your configured path) is writable AND unlinkable by the PHP process user.
  2. Avoid sharing one XMLWriter/document across concurrent workers; generate unique temp files per process.
  3. Keep the XMLWriter object alive until output is fully written, and let it be collected cleanly; suppress competing cleanup scripts.
  4. Since it throws from __destruct, explicitly delete/check the temp file before the object goes out of scope, or wrap usage so exceptions during shutdown are surfaced while the request still runs.

Example fix

// before
$config->setTempDir('/var/cache/phpword'); // dir owned by root, php-fpm user cannot unlink
// after
$config->setTempDir(sys_get_temp_dir()); // writable and unlinkable by the PHP user
// or: chown/chmod the custom temp dir to the PHP-FPM user (e.g. www-data) with 0700
Defensive patterns

Strategy: try-catch

Validate before calling

$tmp = $config->getTempDir();
$probe = tempnam($tmp, 'pwtest');
if ($probe === false || !@unlink($probe)) {
    throw new RuntimeException("Temp dir not writable/unlinkable: $tmp");
}

Try / catch

try {
    $document = $phpWord->save($target, 'Word2007');
} catch (\PhpOffice\PhpWord\Exception\Exception $e) {
    if (str_contains($e->getMessage(), 'could not be deleted')) {
        @unlink($e->getMessage() ? extractPath($e->getMessage()) : null);
        $logger->warning('Stale PhpWord temp file could not be unlinked');
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: The temp file was already removed by another process or a competing writer, permissions on the temp directory changed so the PHP user can no longer unlink it, or the file is held/locked (rare on Linux, e.g. certain mount types/immutable flags).

Common situations: Shared temp directories with restrictive permissions (sys_get_temp_dir() vs /tmp differences); parallel workers processing the same document; cleanup scripts deleting temp files mid-request; PHP-FPM user mismatch after permission changes.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


AI-assisted analysis of PHPOffice/PHPWord@aef95c0415 (2026-09-14). Data as JSON: /api/errors/d1f803e74876ef8f. Report an issue: GitHub.

Appendix: source

Thrown at src/PhpWord/Shared/XMLWriter.php:94

            $this->setIndent(false);
            $this->setIndentString('');
        } else {
            $this->setIndent(true);
            $this->setIndentString('  ');
        }
    }

    /**
     * Destructor.
     */
    public function __destruct()
    {
        // Unlink temporary files
        if (empty($this->tempFileName)) {
            return;
        }
        if (PHP_OS != 'WINNT' && @unlink($this->tempFileName) === false) {
            throw new Exception('The file ' . $this->tempFileName . ' could not be deleted.');
        }
    }

    /**
     * Get written data.
     *
     * @return string
     */
    public function getData()
    {
        if ($this->tempFileName == '') {
            return $this->outputMemory(true);
        }

        $this->flush();

        return file_get_contents($this->tempFileName);
    }

View on GitHub (pinned to aef95c0415)