Version: 0.9.21 · OS: Windows 11 · Browser: Chrome
Summary
On Windows, no image ever renders inline. display_file draws the viewer panel — title bar, zoom
controls, 100% — but the image itself is a broken-image icon, and the size readout shows 0 B.
The backend is fine. The frontend builds the URL from a raw Windows path, without converting
backslashes to forward slashes and without URL-encoding, while the serve endpoint expects
forward slashes — as its own comment says.
Reproduce
- On Windows, open a workspace and put a PNG in it.
- Ask the agent to
display_file that PNG (or open it from the file browser).
- The viewer frame appears; the image is broken; size reads
0 B.
Root cause
Frontend — _app/immutable/nodes/2.*.js:
`/api/workspace/files/serve/${n.filePath.startsWith('/') ? n.filePath.slice(1) : n.filePath}`
n.filePath on Windows is e.g. C:\Users\user\workspace\example.png (confirmed — it appears
verbatim as the broken image's alt text). It is interpolated raw: no separator normalisation,
no encoding.
Backend — routers/workspace.py:
@router.get("/serve/{file_path:path}")
async def serve_static(file_path: str):
# Windows paths arrive as "C:/Users/..." - don't prepend /
if len(file_path) >= 2 and file_path[1] == ":":
target = Path(file_path).resolve()
else:
target = Path("/" + file_path).resolve()
The comment states the contract — C:/Users/..., forward slashes — which the frontend does
not meet.
Evidence the backend is correct
This URL, in a logged-in browser, renders the image correctly:
http://127.0.0.1:8000/api/workspace/files/serve/C:/Users/user/workspace/example.png
Same file, same session, forward slashes instead of backslashes. So routing, auth, MIME detection
and streaming all work; only the URL the frontend builds is wrong.
Suggested fix
Normalise separators before interpolating, and encode each segment:
const p = n.filePath.replace(/\\/g, '/');
const url = `/api/workspace/files/serve/${p.split('/').map(encodeURIComponent).join('/')}`;
Encoding also fixes paths containing spaces, # or ?, which will fail on every platform.
Related: the bundle already has a resolver, de(), which prefers full_path, falls back to
path, and joins relative paths to the workspace root. The image viewer bypasses it — and de()
does not normalise separators either, so both call sites likely need the same treatment.
Workaround in use
Until this is fixed upstream, we patch the built bundle in place, rewriting the interpolation to
normalise separators. It works, but it is a stopgap: an upgrade replaces the bundle and silently
reverts it, so the patch has to be re-applied and verified after every update. A fix in the
source is the real answer.
Anyone hitting this before a release can also open the file directly at
/api/workspace/files/view?path=<url-encoded absolute path>, which serves correctly.
Version: 0.9.21 · OS: Windows 11 · Browser: Chrome
Summary
On Windows, no image ever renders inline.
display_filedraws the viewer panel — title bar, zoomcontrols,
100%— but the image itself is a broken-image icon, and the size readout shows0 B.The backend is fine. The frontend builds the URL from a raw Windows path, without converting
backslashes to forward slashes and without URL-encoding, while the serve endpoint expects
forward slashes — as its own comment says.
Reproduce
display_filethat PNG (or open it from the file browser).0 B.Root cause
Frontend —
_app/immutable/nodes/2.*.js:`/api/workspace/files/serve/${n.filePath.startsWith('/') ? n.filePath.slice(1) : n.filePath}`n.filePathon Windows is e.g.C:\Users\user\workspace\example.png(confirmed — it appearsverbatim as the broken image's
alttext). It is interpolated raw: no separator normalisation,no encoding.
Backend —
routers/workspace.py:The comment states the contract —
C:/Users/..., forward slashes — which the frontend doesnot meet.
Evidence the backend is correct
This URL, in a logged-in browser, renders the image correctly:
Same file, same session, forward slashes instead of backslashes. So routing, auth, MIME detection
and streaming all work; only the URL the frontend builds is wrong.
Suggested fix
Normalise separators before interpolating, and encode each segment:
Encoding also fixes paths containing spaces,
#or?, which will fail on every platform.Related: the bundle already has a resolver,
de(), which prefersfull_path, falls back topath, and joins relative paths to the workspace root. The image viewer bypasses it — andde()does not normalise separators either, so both call sites likely need the same treatment.
Workaround in use
Until this is fixed upstream, we patch the built bundle in place, rewriting the interpolation to
normalise separators. It works, but it is a stopgap: an upgrade replaces the bundle and silently
reverts it, so the patch has to be re-applied and verified after every update. A fix in the
source is the real answer.
Anyone hitting this before a release can also open the file directly at
/api/workspace/files/view?path=<url-encoded absolute path>, which serves correctly.