Windows: render_docx.py passes invalid file:// URI to LibreOffice UserInstallation
Bug: render_docx.py builds invalid Windows file:// URI for LibreOffice UserInstallation
Component
Codex App / documents skill / render_docx.py
Environment
- OS: Microsoft Windows 10.0.26200, x64
- Codex CLI:
codex-cli 0.142.2 - LibreOffice:
LibreOffice 26.2.2.2 1f77d10d6938fd34972958f64b2bcfa54f8b1ba5 - Shell: PowerShell
Summary
On Windows, render_docx.py passes a Windows path to LibreOffice as:
-env:UserInstallation=file://C:\Users\...\AppData\Local\Temp\soffice_profile_xxx
LibreOffice fails before producing the PDF and prints:
libpng error: Write Error
The same conversion succeeds when UserInstallation is expressed as a valid Windows file URI:
-env:UserInstallation=file:///C:/Users/.../AppData/Local/Temp/soffice_profile_xxx
Reproduction
- On Windows, run the bundled documents renderer against any valid
.docx:
& "<codex-runtime-python>\python.exe" `
"<codex-documents-skill>\render_docx.py" `
"D:\path\sample.docx" `
--output_dir "D:\path\rendered" `
--verbose `
--emit_pdf
- The script constructs a LibreOffice command like:
soffice -env:UserInstallation=file://C:\Users\...\AppData\Local\Temp\soffice_profile_xxx --invisible --headless --norestore --convert-to pdf --outdir C:\Users\...\AppData\Local\Temp\soffice_convert_xxx D:\path\sample.docx
- LibreOffice exits with code 1 and stderr:
libpng error: Write Error
- No PDF is produced, and
render_docx.pyraises:
RuntimeError: Failed to produce PDF for rasterization (direct and ODT fallback).
Expected behavior
render_docx.py should produce a PDF and PNG pages on Windows when LibreOffice is installed and the input DOCX is valid.
Actual behavior
PDF generation fails because LibreOffice receives an invalid UserInstallation file URI.
Evidence
The same input document and LibreOffice installation were tested with two UserInstallation forms:
file://D:\...\lo_profile -> fails with "libpng error: Write Error"
file:///D:/.../lo_profile -> succeeds and generates the PDF
Running LibreOffice without the isolated profile can also generate the PDF, but that is not a good long-term workaround because it uses the default user profile and can be affected by profile locks or user configuration.
Likely cause
render_docx.py currently constructs the argument by string concatenation:
"-env:UserInstallation=file://" + user_profile
On Windows this produces a non-standard file URI with backslashes and no third slash after file:.
Suggested fix
Use platform-aware URI construction, for example:
from pathlib import Path
"-env:UserInstallation=" + Path(user_profile).resolve().as_uri()
This produces file:///C:/... on Windows and valid file URIs on other platforms.
15 Comments
I can reproduce a closely related Windows failure on another Codex Desktop install, with one additional symptom that may help debugging.
Environment:
openai-primary-runtime/documents/26.630.11634LibreOffice 26.2.4.2 0229ac93fcf0d7cbc6376066c6f35021cef002dcObserved behavior:
render_docx.py, LibreOffice can show a GUI error dialog in Chinese:The application cannot be started. The configuration file "C:\Program Files\LibreOffice\program\bootstrap.ini" is corrupt.C:\Program Files\LibreOffice\program\bootstrap.iniis readable and normal, and direct LibreOffice conversion works.-env:UserInstallation=file://C:\Users\win\AppData\Local\Temp\soffice_profile_...Local fix that worked:
Path(user_profile).resolve().as_uri():-env:UserInstallation=file:///C:/Users/win/AppData/Local/Temp/soffice_profile_...soffice.exeexplicitly. Using plainsofficemay resolve through Windows command lookup in a way that is harder to diagnose.pdf2image:.../dependencies/native/poppler/Library/binAfter applying those local changes, the same test DOCX rendered successfully to
page-1.png, with no leftover LibreOffice processes.So the misleading
bootstrap.ini is corruptdialog appears to be another manifestation of the malformed Windowsfile://UserInstallationargument rather than an actual LibreOffice installation corruption.I hit this on Windows with the bundled documents runtime
openai-primary-runtime/documents/26.630.12135and confirmed the root cause/fix locally.The cached renderer contains three instances of:
On Windows this builds an invalid URI, for example:
LibreOffice then fails conversion with:
and may show the misleading dialog that
C:\Program Files\LibreOffice\program\bootstrap.iniis corrupt.I verified the same LibreOffice install succeeds when the URI is built with
Path.as_uri():That produces the valid Windows form:
Local validation after patching
render_docx.py:Output files were produced successfully:
The public
openai/codexrepo appears to referenceopenai-primary-runtimeas a plugin/runtime, but I could not find the actualdocuments/render_docx.pysource in the public tree, so I cannot submit a direct source PR for this file. The minimal runtime patch is to constructUserInstallationwithPath(user_profile).resolve().as_uri()anywhere this command argument is assembled.I can reproduce this on a newer Codex Desktop documents bundle.
Environment:
openai-primary-runtime/documents/26.709.1151626.2.4.2Observed behavior:
render_docx.pystill constructs the profile argument as:``
text
``-env:UserInstallation=file://C:\Users\<USER>\AppData\Local\Temp\soffice_profile_xxx
PATH, so the unmodified renderer can first fail withFileNotFoundError: [WinError 2]when it invokes baresoffice.``
text
``libpng error: Write Error
LibreOffice also displayed the misleading Chinese GUI dialog saying that
C:\Program Files\LibreOffice\program\bootstrap.iniwas corrupt. The file is readable and appears normal.Controlled comparison with the same trivial DOCX:
C:\Program Files\LibreOffice\program\soffice.comUserInstallationgenerated as a real URI (file:///C:/...)completed with exit code 0 and produced a non-empty PDF. The bundled Poppler/pdf2image path also reads the resulting PDF successfully.
This confirms the issue is still present in bundle
26.709.11516. For this Windows environment the local workaround needs both:Path(user_profile).resolve().as_uri()forUserInstallation; andsoffice.cominstead of relying on baresoffice/PATH lookup.Confirmed on a newer Codex Desktop/Documents bundle. The issue is still present as of 2026-07-24.
Environment:
26.721.4979.010.0.26200, x64openai-primary-runtime/documents/26.723.1221526.2.4.2Observed behavior:
python-docxand opened normally in Microsoft Word.render_docx.pyinvoked LibreOffice with:``
text
``-env:UserInstallation=file://C:\Users\<USER>\AppData\Local\Temp\soffice_profile_xxx
1:``
text
``libpng error: Write Error
``
text
``Cannot start application.
Configuration file "C:\Program Files\LibreOffice\program\bootstrap.ini" is corrupted.
Controlled comparison:
UserInstallationargument succeeded and produced a non-empty PDF of approximately 483 KB:``
text
``soffice.com --headless --convert-to pdf --outdir <output> <document.docx>
This adds another independent reproduction showing that the DOCX, LibreOffice installation, and document filename are not the root cause. The malformed Windows file URI remains the strongest explanation. The renderer still contains three occurrences of:
Using
Path(user_profile).resolve().as_uri()and resolvingsoffice.comexplicitly on Windows appears to be the appropriate fix.Why this likely escaped detection on non-Windows (Windows-specific note):
Adding some context on why this passes elsewhere: on macOS/Linux,
tempfile.TemporaryDirectory()returns a path beginning with/(e.g./var/folders/.../soffice_profile_xxxor/tmp/soffice_profile_xxx). The renderer's"file://" + user_profiletherefore yieldsfile:///var/folders/...— a valid file URI, because the path's leading slash supplies the missing third slash afterfile:. On Windows the temp path isC:\..., so the same concatenation produces the malformedfile://C:\...(two slashes instead of three, illegal backslashes,C:parsed as the authority/host).This is consistent with every reproduction in this thread being Windows-only, and explains why the same code path does not fail on macOS/Linux dev or CI machines. The
Path(user_profile).resolve().as_uri()fix proposed above generates correct file URIs on all platforms, so it should close the gap without regressing non-Windows.Additional Confirmation & Production Workaround
We've encountered the exact same issue in production with real customers on Windows.
Our Environment
Production Impact
render_docx.pylines 205, 233, 251 all use"file://" + user_profileDetailed Diagnostic Report
We conducted a comprehensive diagnostic following the methodology in our support toolkit. Key findings:
soffice_profile_*directories: 18 leaked instancesWorkaround Solution
We've created an automated fix script for affected users:
Fix-Codex-Plugin-Windows.ps1Path.as_uri()support/codex/The fix script is now part of our release package to help users until upstream fix is available.
Reference Implementation
Our project (Bidwise) uses a similar pattern in our Base 1.0.2
soffice-headless.cjs:This correctly generates
file:///C:/Users/...on Windows.Request
This bug affects all Windows Codex users. The fix is straightforward (3 lines). Could this be prioritized? We're happy to provide:
We're distributing the workaround with our releases, but an upstream fix would benefit the entire Windows Codex ecosystem.
---
Reported by: Bidwise Team (bidwise.ai)
Related: Customer diagnostic report available on request
Additional confirmation from another Windows Codex Desktop installation.
This bug has recurred after each Documents plugin/runtime update. I observed it in these bundled Documents versions:
26.521.1041926.715.1214326.723.12215In every version,
render_docx.pyagain contained:On Windows this spawned LibreOffice with an argument such as:
LibreOffice 26.2.4.2 repeatedly displayed a misleading GUI error in Chinese saying that
C:\Program Files\LibreOffice\program\bootstrap.iniwas corrupted, while the Codex document-rendering process remained stuck. LibreOffice itself was healthy: direct headless DOCX-to-PDF conversion worked.Changing the argument to:
produced
file:///C:/Users/..., stopped the popup, and successfully rendered a 16-page DOCX to PNG pages. However, each Documents plugin update replaced the patched cached script and reintroduced the bug.So this is both a Windows URI-construction bug and an update-persistence issue. The fix needs to be shipped in the upstream Documents plugin/runtime rather than applied to the local cache.
Additional reproduction data from another Windows Codex Desktop environment:
openai-primary-runtime/documents/26.727.11326.LibreOffice 26.2.4.2 0229ac93fcf0d7cbc6376066c6f35021cef002dcinstalled at the default path.C:\Program Files\LibreOffice\program\bootstrap.iniis damaged.bootstrap.iniwas not actually damaged. LibreOffice launched normally withsoffice.com --version.The stuck LibreOffice process was launched with the invalid Windows file URI form:
The same local fix worked here:
After patching the helper to use
Path(...).resolve().as_uri(), a DOCX smoke test rendered successfully to both PDF and page PNG, and nofile://C:\...LibreOffice process remained.One recurrence detail: because the helper lives inside versioned Codex runtime cache folders, the local fix has to be reapplied when a new
openai-primary-runtime/documents/...cache version appears. This environment had seen the same bad pattern across multiple cache versions, including26.709.11516,26.715.12143,26.723.12215, and now26.727.11326.Additional production confirmation: this bug is still present in the newest official Documents plugin delivered to our installation as of 2026-07-28.
Environment:
0.145.026.727.11326.codex-plugin/plugin.json: OpenAIThe unmodified
render_docx.pyhas SHA-256:It still contains the malformed Windows URI construction at all three conversion call sites, currently lines 205, 233, and 251:
There is no
Path(user_profile).as_uri()or equivalent platform-aware URI construction in this version. In a real Windows customer environment this still produces the LibreOfficebootstrap.inidamaged/corrupted dialog and prevents the expected conversion output.We verified the same narrow patch at all three call sites:
After applying it, headless DOCX/ODT-to-PDF conversions completed with exit code 0, including parallel conversions, without the popup or temporary-profile residue. A subsequent plugin refresh replaces the patched file, so downstream users still need to reapply the workaround.
Please include the platform-aware URI construction at all three call sites in the official Documents plugin release.
Additional confirmation on a newer Codex Desktop/Documents bundle.
Environment:
26.721.11231.0openai-primary-runtime/documents/26.730.1171010.0.26200, x6426.2.4.2019fb707-e284-7ff0-97cd-44d0d44e4653Observed behavior:
render_docx.pystill contains three instances of"file://" + user_profileat the direct PDF, ODT fallback, and ODT-to-PDF call sites.-env:UserInstallation=file://C:\Users\....libpng error: Write Error; no PDF is produced.Controlled comparison:
[System.Uri]::new($profileDir).AbsoluteUriproducesfile:///C:/Users/....26.730.11710.Suggested fix remains
Path(user_profile).resolve().as_uri()at all three call sites.Still reproducible on a newer documents runtime bundle as of 2026-08-06:
openai-primary-runtime/documents/26.802.11031cd7284b4cbbfeb507e630c1aac019f4157393acb)The cached
render_docx.pyin this bundle still contains the three"-env:UserInstallation=file://" + user_profileinstances, producing:soffice.exe then shows the localized (Korean, in our case) "bootstrap.ini is corrupt" fatal dialog and hangs until the dialog is dismissed, so users see the dialog repeatedly on every render attempt.
Confirmed the
Path(user_profile).as_uri()fix works on this setup (conversion succeeds, no dialog, no leftover soffice processes).One additional data point for triage: the failure mode depends on the exact malformed value passed to
-env:UserInstallation:file://C:\...(two slashes + backslashes, current bug) → fatal dialog "configuration file bootstrap.ini is corrupt" + hangC:/...(no scheme) → silent failure: exit code 0, no output, no PDF producedSo depending on how the argument gets mangled, the script can also fail silently with exit 0, which is worth guarding against in addition to the URI fix.
Still reproducible after another Documents runtime update on 2026-08-07.
Environment:
26.803.5235.00.144.1openai-primary-runtime/documents/26.805.1174010.0.19045.7548, x6426.2.3.2The unmodified renderer backup (SHA-256
85BDD05ABB4F3F7BE5860BC000FAC34BC176C4B48148723E52BB97328D8007FB) still contains the malformed Windows URI construction at all three conversion call sites:This again triggered the misleading LibreOffice dialog reporting that
C:\Program Files\LibreOffice\program\bootstrap.iniwas corrupt. The LibreOffice installation andbootstrap.iniwere healthy.A previous local fix had been applied to runtime
26.802.11031, but the update to26.805.11740replaced the versioned runtime directory and reintroduced the same bug.I reapplied the narrow platform-aware fix:
Validation using the updated bundle's own
render_docx.pyagainst a valid DOCX:0313,067bytes466,015bytesThis confirms that the defect remains in bundle
26.805.11740and that runtime updates continue to overwrite the working local patch. Please shipPath(...).resolve().as_uri()(or equivalent platform-aware URI construction) at all three call sites in the upstream Documents runtime.All user names and document paths have been omitted.
Confirming this is still present in a newer Windows bundle.
Environment:
26.805.1174026.2.4.2The same malformed argument is generated:
-env:UserInstallation=file://C:\Users\<user>\AppData\Local\Temp\soffice_profile_*Additional symptom: after several Codex document-rendering launches, LibreOffice can show a GUI modal saying:
The application cannot be started. The configuration file "C:\Program Files\LibreOffice\program\bootstrap.ini" is corrupt.We verified that
bootstrap.iniexists, is readable, and its hash/mtime remain unchanged; relevant LibreOffice/UNO environment overrides are unset. The message is therefore misleading in this case.Local patch:
After patching all three conversion call sites, 5 consecutive end-to-end
render_docx.pyruns completed successfully (PDF plus PNG pages on every run), with no lingeringsofficeprocesses or error dialogs.This confirms the issue is still reproducible in Documents
26.805.11740and that URI normalization resolves it; reinstalling LibreOffice is not required.Additional NTFS/VSS/MSI forensic confirmation from a current Windows installation. This adds evidence that the recurring
bootstrap.ini is corruptdialog can occur without any mutation of that file.Environment
10.0.26200.803726.803.5235.00.147.0openai-primary-runtime/documents/26.805.11740render_docx.pySHA-256:85BDD05ABB4F3F7BE5860BC000FAC34BC176C4B48148723E52BB97328D8007FB26.2.5.2, x64The current renderer still contains all three instances of:
Forensic evidence
C:\Program Files\LibreOffice\program\bootstrap.iniis 112 bytes, valid ASCII/UTF-8 without BOM, and has SHA-256:9BC1FFA0360ADACAD9666D1B9D5BE2B09E3F9FF1EB851A05F168393819CBABE0.bootstrap.iniand its file reference number returns zero records.11:52:10, the same USN journal records creation of bothsoffice_profile_*andsoffice_convert_*temporary directories. A bounded search of the installed Codex scripts/runtime finds thisrender_docx.pyas the only local generator of that exact prefix pair. The corresponding Prefetch sequence contains a LibreOffice launch.UserInstallationbootstrap data to the generic message that the existingbootstrap.inifile “is corrupt”: https://github.com/LibreOffice/core/blob/libreoffice-26.2.5.2/unotools/source/config/bootstrap.cxx#L235-L480Therefore, in this captured episode there was no ordinary NTFS writer corrupting or restoring
bootstrap.ini. The dialog was a misleading consequence of the malformed runtime override. This matters because users may repeatedly repair or reinstall a healthy LibreOffice installation.The upstream correction remains:
Please apply it at all three call sites and add a Windows regression test asserting a
file:///C:/...URI. A cache-only patch is not durable because Documents runtime updates replace the versioned directory.No user names, document paths, document contents, screenshots, credentials, or private logs are included.
Additional independent verification on Windows using the bundled Documents package version
26.805.11740and LibreOffice25.8.7.3on August 12, 2026.I repeated the A/B comparison twice against the same test DOCX containing two embedded PNG images, changing only the
UserInstallationURI form. In both repetitions:file://C:\...caused LibreOffice to exit with code 1 and reportlibpng error: Write Error; it produced no PDF and did not initialize the temporary profile.file:///C:/...caused LibreOffice to exit with code 0, produce a non-empty PDF, and initialize the temporary profile normally.I then patched all three call sites to construct the profile URI as follows:
A task-local copy of the patched renderer completed an end-to-end conversion of a separate three-page DOCX, producing one PDF and three page PNGs. After applying the same patch to the installed renderer, I repeated the end-to-end test and again obtained one PDF and three page PNGs.
These results provide another controlled A/B confirmation that the URI construction is the failure point. In my installation of bundle
26.805.11740,Path(...).resolve().as_uri()resolved this URI-related LibreOffice conversion failure. Related reports: #24210 and #27957.