frappe / frappe/toolbox

PWA manifest is served as application/octet-stream rather than application/manifest+json

Open
#271 1 comment 0 reactions 0 assignees View on GitHub
bug severity:P3
Dominant language
JavaScript
Stars
5
Forks
1
Avg merge
1h 25m
Merged PRs (30d)
1

Description

Production serves the web app manifest as a binary blob, and tells the browser not to guess otherwise. **Installing Toolbox as an app is very likely broken on the live site.**

```
$ curl -sI https://frappe.tools/assets/toolbox/pwa/manifest.webmanifest
content-type: application/octet-stream
x-content-type-options: nosniff
x-proxy-cache: HIT
```

The file itself is fine — valid JSON, correct contents. The problem is the two headers together. `application/octet-stream` tells the browser this is not a manifest, and `nosniff` forbids it from working that out from the content. A browser that cannot read the manifest offers no install prompt.

The image beside it is served correctly (`image/png`), so this is specific to the `.webmanifest` extension having no MIME mapping on the proxy.

## Why nothing caught it before

Locally the development server maps `.webmanifest` correctly, so `smoke.spec.js` has always passed. It took `bash qa/run-qa.sh --target=prod`, which runs the read-only checks against the live site, to see it. The assertion that failed was already there and already right:

```js
expect(manifestResponse.headers()['content-type']).toContain('application/manifest+json')
```

## Where it cannot be fixed

Not in the application. `x-proxy-cache: HIT` and the absence of `x-page-name` show the proxy serves this file directly; the request never reaches Frappe, so no `after_request` hook, route or template can change the header.

## Two ways to fix it

**Rename the file to `manifest.json`.** The proxy already maps `.json` to `application/json`, which browsers accept for a manifest. It stays a static asset, cached and fast. Costs: the Vite PWA plugin's output name, the `` in the shell, the service worker precache list, `manifest.test.js`, and the assertion above. All in this repository, all covered by tests.

**Serve it through a Frappe route**, the way `robots.txt` and `sitemap.xml` already are, setting `application/manifest+json` explicitly. Exactly correct rather than merely accepted, but it turns a cacheable static file into a Python response on every install check.

The first is smaller and lower risk. The second is more correct.

## Worth confirming first

Open `frappe.tools` in Chrome, then DevTools → Application → Manifest. If it reports the manifest cannot be fetched or parsed, that confirms installation is broken rather than merely non-standard. Worth doing before choosing a fix, because it tells you whether this is urgent or tidy-up.

## Not caused by anything recent

The manifest has been served this way for as long as the PWA has existed. This is a pre-existing defect that the production sweep found, not a regression.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with bash qa/run-qa.sh --target=prod and inspect smoke.spec.js, manifest.test.js, the Vite PWA output name, the shell manifest link, and the service-worker precache list. Choose and document the lower-risk static-asset fix or the Frappe route, update the affected references and tests, then confirm the production response is accepted as a web manifest and the PWA checks pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, vite
Domain
frontend, infrastructure, web-dev
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
64/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.