[GH-ISSUE #248] bug: File preview serves stale content for unchanged file paths #162

Open
opened 2026-10-18 14:03:28 +00:00 by bsakaguchi · 2 comments
Owner

Originally created by @JKGeovision on GitHub (Aug 31, 2026).
Original GitHub issue: https://github.com/open-webui/computer/issues/248

Hello,

I discovered that the in-app file preview keeps showing stale content when a workspace file is modified in place (same path, new content), because the mutable file endpoints send no cache policy and the preview refresh does not bypass the browser cache.

Steps to reproduce:

  1. Create an HTML file in the workspace (e.g. a generated report).
  2. Open it from the chat file card (HTML preview in the app).
  3. Modify or regenerate the file in place (same path, new content, new mtime).
  4. Re-open the preview and/or press the refresh button in the preview header (multiple times).
  5. Observe that the stale version is still rendered, even after several refreshes.
  6. Copy the new content to a file with a different name and preview it. The new content is shown immediately.

Expected behavior:

  • The preview renders the updated file content after the file is modified in place.

Actual behavior:

  • The preview keeps rendering the stale version indefinitely. Pressing the refresh button or re-opening the preview does not help.

Root cause analysis:

  1. Backend: mutable file endpoints send no cache policy

cptr/routers/workspace.py defines three mutable file endpoints:

  • serve_static() for GET /api/workspace/files/serve/{file_path:path} (lines 911-935)
  • view_file() for GET /api/workspace/files/view (lines 813-834)
  • download_file() for GET /api/workspace/files/download (lines 840-854)

All three return a plain FileResponse with no Cache-Control or Expires header. Measured live response for the /serve endpoint:

HTTP/1.1 200 OK
content-type: text/html; charset=utf-8
accept-ranges: bytes
content-length: 236299
last-modified: Mon, 31 Aug 2026 16:13:17 GMT
etag: "6b640272f48391eebd93dfeb0a538543"

(no Cache-Control, no Expires)

Without a cache directive, browsers and WebViews apply heuristic caching to 200 responses and may serve the stored body for an unbounded time. These endpoints serve mutable files behind stable path-based URLs, which is exactly the case that requires an explicit cache policy.

Note: the server also ignores If-None-Match (always 200, never 304). I verified this by re-requesting with the previous ETag after modifying the file, so even a revalidating client cannot benefit server-side. The observed behavior indicates the client does not even revalidate.

Contrast: routers/files.py:82 (immutable upload blobs) correctly sends Cache-Control: public, max-age=31536000, immutable, so the workspace file endpoints appear to have simply been missed.

  1. Frontend: preview uses a stable URL and a cache-respecting reload

In the bundled frontend build (cptr 0.9.21, frontend/build/_app/immutable/nodes/2.*.js), the chat HTML preview renders:

<iframe sandbox="allow-scripts allow-same-origin" class="preview-iframe"></iframe>

with src set to /api/workspace/files/serve/${filePath}, a stable URL per file path. The preview toolbar's reload action performs a plain iframe.contentWindow.location.reload(). A regular location.reload() respects the HTTP cache (no cache-busting parameter, no bypass), so once the WebView has cached the 200 response for that URL, the refresh button re-serves the cached body.

Suggested fixes:

  • Server (recommended, fixes all clients): add an explicit cache policy to the mutable file endpoints (/api/workspace/files/serve/*, /view, /download), either Cache-Control: no-store (simplest), or Cache-Control: no-cache plus 304 handling for If-None-Match / If-Modified-Since. The ETag and Last-Modified headers are already sent by FileResponse, so revalidation would be cheap.
  • Frontend (defense in depth): append a cache-busting query parameter to the preview iframe URL on every open and on refresh (e.g. ?v=<file mtime> or ?t=<Date.now()>). The /serve route is path-based and ignores the query string, so this works without any server change. Alternatively, make the refresh action perform a cache-bypassing reload.

Workaround:

Preview a copy under a new file name, or open the file in an external browser.

Thank you for your time and consideration.

Best regards,
Joshua Krimmer

Originally created by @JKGeovision on GitHub (Aug 31, 2026). Original GitHub issue: https://github.com/open-webui/computer/issues/248 Hello, I discovered that the in-app file preview keeps showing stale content when a workspace file is modified in place (same path, new content), because the mutable file endpoints send no cache policy and the preview refresh does not bypass the browser cache. Steps to reproduce: 1. Create an HTML file in the workspace (e.g. a generated report). 2. Open it from the chat file card (HTML preview in the app). 3. Modify or regenerate the file in place (same path, new content, new mtime). 4. Re-open the preview and/or press the refresh button in the preview header (multiple times). 5. Observe that the stale version is still rendered, even after several refreshes. 6. Copy the new content to a file with a different name and preview it. The new content is shown immediately. Expected behavior: - The preview renders the updated file content after the file is modified in place. Actual behavior: - The preview keeps rendering the stale version indefinitely. Pressing the refresh button or re-opening the preview does not help. Root cause analysis: 1. Backend: mutable file endpoints send no cache policy `cptr/routers/workspace.py` defines three mutable file endpoints: - `serve_static()` for `GET /api/workspace/files/serve/{file_path:path}` (lines 911-935) - `view_file()` for `GET /api/workspace/files/view` (lines 813-834) - `download_file()` for `GET /api/workspace/files/download` (lines 840-854) All three return a plain `FileResponse` with no `Cache-Control` or `Expires` header. Measured live response for the `/serve` endpoint: ```http HTTP/1.1 200 OK content-type: text/html; charset=utf-8 accept-ranges: bytes content-length: 236299 last-modified: Mon, 31 Aug 2026 16:13:17 GMT etag: "6b640272f48391eebd93dfeb0a538543" ``` (no `Cache-Control`, no `Expires`) Without a cache directive, browsers and WebViews apply heuristic caching to 200 responses and may serve the stored body for an unbounded time. These endpoints serve mutable files behind stable path-based URLs, which is exactly the case that requires an explicit cache policy. Note: the server also ignores `If-None-Match` (always 200, never 304). I verified this by re-requesting with the previous ETag after modifying the file, so even a revalidating client cannot benefit server-side. The observed behavior indicates the client does not even revalidate. Contrast: `routers/files.py:82` (immutable upload blobs) correctly sends `Cache-Control: public, max-age=31536000, immutable`, so the workspace file endpoints appear to have simply been missed. 2. Frontend: preview uses a stable URL and a cache-respecting reload In the bundled frontend build (cptr 0.9.21, `frontend/build/_app/immutable/nodes/2.*.js`), the chat HTML preview renders: ```html <iframe sandbox="allow-scripts allow-same-origin" class="preview-iframe"></iframe> ``` with `src` set to `/api/workspace/files/serve/${filePath}`, a stable URL per file path. The preview toolbar's reload action performs a plain `iframe.contentWindow.location.reload()`. A regular `location.reload()` respects the HTTP cache (no cache-busting parameter, no bypass), so once the WebView has cached the 200 response for that URL, the refresh button re-serves the cached body. Suggested fixes: - Server (recommended, fixes all clients): add an explicit cache policy to the mutable file endpoints (`/api/workspace/files/serve/*`, `/view`, `/download`), either `Cache-Control: no-store` (simplest), or `Cache-Control: no-cache` plus 304 handling for `If-None-Match` / `If-Modified-Since`. The `ETag` and `Last-Modified` headers are already sent by `FileResponse`, so revalidation would be cheap. - Frontend (defense in depth): append a cache-busting query parameter to the preview iframe URL on every open and on refresh (e.g. `?v=<file mtime>` or `?t=<Date.now()>`). The `/serve` route is path-based and ignores the query string, so this works without any server change. Alternatively, make the refresh action perform a cache-bypassing reload. Workaround: Preview a copy under a new file name, or open the file in an external browser. Thank you for your time and consideration. Best regards, Joshua Krimmer
Author
Owner

@owui-terminator[bot] commented on GitHub (Aug 31, 2026):

🔍 Related Issues Found

I found some existing issues that might be related. Please check if any of these are duplicates or contain helpful solutions:

  1. 🟢 #246 bug: image previews never render on Windows — frontend sends backslash paths to /api/workspace/files/serve
    Shares the same /api/workspace/files/serve preview path and the same frontend preview mechanism. While this issue is about Windows path formatting rather than caching, it confirms the relevant code path and file preview subsystem affected by workspace file rendering.
    by gucazcode

  2. 🟢 #164 bug: problematic cache reuse
    Broad cache-related issue, but it concerns inference/prompt caching rather than HTTP/browser caching. It is only tangentially related, so it is a weak match for the new file-preview stale-content bug.
    by cclecle


💡 If your issue is a duplicate, please close it and add any additional details to the existing issue instead.

This comment was generated automatically. React with 👍 if helpful, 👎 if not.

<!-- gh-comment-id:5485341031 --> @owui-terminator[bot] commented on GitHub (Aug 31, 2026): <!-- terminator-bot:related-issues-reply --> 🔍 **Related Issues Found** I found some existing issues that might be related. Please check if any of these are duplicates or contain helpful solutions: 1. 🟢 [#246](https://github.com/open-webui/computer/issues/246) **bug: image previews never render on Windows — frontend sends backslash paths to `/api/workspace/files/serve`** *Shares the same `/api/workspace/files/serve` preview path and the same frontend preview mechanism. While this issue is about Windows path formatting rather than caching, it confirms the relevant code path and file preview subsystem affected by workspace file rendering.* *by gucazcode* 2. 🟢 [#164](https://github.com/open-webui/computer/issues/164) **bug: problematic cache reuse** *Broad cache-related issue, but it concerns inference/prompt caching rather than HTTP/browser caching. It is only tangentially related, so it is a weak match for the new file-preview stale-content bug.* *by cclecle* --- 💡 If your issue is a duplicate, please close it and add any additional details to the existing issue instead. *This comment was generated automatically.* React with 👍 if helpful, 👎 if not.
Author
Owner

@Classic298 commented on GitHub (Sep 21, 2026):

just hit this from the agent side, not the file explorer: display_file on the same path twice in one chat shows the first render's bytes the second time. agent regenerates the file on disk (new mtime, new size), the inline chat preview stays stale. renaming the path shows the new bytes immediately, which matches the cache diagnosis here.

the workspace file endpoints sending no cache policy is the whole story for me too, the immutable upload endpoint does it correctly. no-cache on the mutable ones would fix both the explorer preview and the chat file cards.

<!-- gh-comment-id:5766436310 --> @Classic298 commented on GitHub (Sep 21, 2026): just hit this from the agent side, not the file explorer: display_file on the same path twice in one chat shows the first render's bytes the second time. agent regenerates the file on disk (new mtime, new size), the inline chat preview stays stale. renaming the path shows the new bytes immediately, which matches the cache diagnosis here. the workspace file endpoints sending no cache policy is the whole story for me too, the immutable upload endpoint does it correctly. no-cache on the mutable ones would fix both the explorer preview and the chat file cards.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
open-webui/computer#162
No description provided.