{"record":{"id":"d1f803e74876ef8f","repo":"PHPOffice/PHPWord","slug":"the-file-tempfilename-could-not-be-deleted","errorCode":null,"errorMessage":"The file {tempFileName} could not be deleted.","messagePattern":"The file (.+?) could not be deleted\\.","errorType":"exception","errorClass":"PhpOffice\\PhpWord\\Exception\\Exception","httpStatus":null,"severity":"warning","filePath":"src/PhpWord/Shared/XMLWriter.php","lineNumber":94,"sourceCode":"            $this->setIndent(false);\n            $this->setIndentString('');\n        } else {\n            $this->setIndent(true);\n            $this->setIndentString('  ');\n        }\n    }\n\n    /**\n     * Destructor.\n     */\n    public function __destruct()\n    {\n        // Unlink temporary files\n        if (empty($this->tempFileName)) {\n            return;\n        }\n        if (PHP_OS != 'WINNT' && @unlink($this->tempFileName) === false) {\n            throw new Exception('The file ' . $this->tempFileName . ' could not be deleted.');\n        }\n    }\n\n    /**\n     * Get written data.\n     *\n     * @return string\n     */\n    public function getData()\n    {\n        if ($this->tempFileName == '') {\n            return $this->outputMemory(true);\n        }\n\n        $this->flush();\n\n        return file_get_contents($this->tempFileName);\n    }","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/PHPOffice/PHPWord/blob/aef95c04151b5633cc505f672ddd6a71da900ee1/src/PhpWord/Shared/XMLWriter.php#L76-L112","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Ensure the temp directory (from sys_get_temp_dir() or your configured path) is writable AND unlinkable by the PHP process user.","Avoid sharing one XMLWriter/document across concurrent workers; generate unique temp files per process.","Keep the XMLWriter object alive until output is fully written, and let it be collected cleanly; suppress competing cleanup scripts.","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."],"exampleFix":"// before\n$config->setTempDir('/var/cache/phpword'); // dir owned by root, php-fpm user cannot unlink\n// after\n$config->setTempDir(sys_get_temp_dir()); // writable and unlinkable by the PHP user\n// or: chown/chmod the custom temp dir to the PHP-FPM user (e.g. www-data) with 0700","handlingStrategy":"try-catch","validationCode":"$tmp = $config->getTempDir();\n$probe = tempnam($tmp, 'pwtest');\nif ($probe === false || !@unlink($probe)) {\n    throw new RuntimeException(\"Temp dir not writable/unlinkable: $tmp\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    $document = $phpWord->save($target, 'Word2007');\n} catch (\\PhpOffice\\PhpWord\\Exception\\Exception $e) {\n    if (str_contains($e->getMessage(), 'could not be deleted')) {\n        @unlink($e->getMessage() ? extractPath($e->getMessage()) : null);\n        $logger->warning('Stale PhpWord temp file could not be unlinked');\n    } else {\n        throw $e;\n    }\n}","preventionTips":["Point the temp dir at a dedicated directory owned by the PHP user with 0700","Avoid concurrent workers sharing one temp path; unique files per process","Exclude temp dirs from external cleanup cron jobs while requests run","Run a deploy-time smoke test that saves and deletes a sample document"],"tags":["phpword","filesystem","temp-file","permissions","destructor"],"backgroundTag":"file-write-permission-denied","analyzedSha":"aef95c04151b5633cc505f672ddd6a71da900ee1","analyzedAt":"2026-09-14T10:53:58.933Z","contentChangedAt":"2026-09-14T10:53:58.933Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}