Skip to content

[BUG] Firefox: viewFileOnlyoffice throws DOMException on Seafile 13 + OnlyOffice 9.4 (works in Chrome/Safari) #3031

Description

@fabianpetre

Summary

Opening any Office file (.docx / .xlsx / .pptx) in Firefox on Seafile 13.0.21 with a working OnlyOffice 9.4.0.1 backend results in a blank editor canvas. The exact same file, account, and JWT configuration render the editor correctly in Safari (and Chrome). The failure is an uncaught DOMException raised inside Seafile's own frontend bundle while mounting the editor, before OnlyOffice's iframe ever finishes initializing.

Steps to reproduce

  1. Deploy Seafile CE 13.0.21 via Docker (seafileltd/seafile-mc:13.0.21).
  2. Deploy OnlyOffice DocumentServer 9.4.0.1 (onlyoffice/documentserver:9.4.0.1) on a separate origin, with JWT_ENABLED=true, JWT_HEADER=Authorization, JWT_IN_BODY=true, and a shared JWT secret.
  3. Configure seahub_settings.py exactly per the official integration guide:
    ENABLE_ONLYOFFICE = True
    ONLYOFFICE_APIJS_URL = 'https://onlyoffice.example.com/web-apps/apps/api/documents/api.js'
    ONLYOFFICE_JWT_SECRET = '<shared secret>'
  4. Open Firefox 151.0.1 on macOS, log in to Seafile, click any .docx file in a library.

Expected behavior

The OnlyOffice editor mounts inside the file-view page and renders the document — the same behavior observed in Safari and Chrome with an identical configuration.

Observed behavior

  • The Seafile file-view toolbar (filename, star, share, info, comments) renders normally.
  • The editor area below the toolbar stays blank.
  • A single Uncaught (in promise) DOMException: An invalid or illegal string was specified appears in the Browser Console, raised from commons.<hash>.js via viewFileOnlyoffice.<hash>.js.
  • All OnlyOffice assets load (HTTP 200) — api.js, sdk-all-min.js (3.5 MB), app.css, fonts, locale data. The editor iframe even fetches its subdocument (index.html?_dc=9.4.0-…&lang=en…), but the DOMException in the parent halts the mount.
  • DocumentServer's docservice/out.log shows zero new requests for the failed session, consistent with the parent-page mount aborting before the editor iframe's bootstrap completes.
  • Reverting to Safari or Chrome (same session, same JWT, same docx) renders the editor immediately.
Image

Error message

Uncaught (in promise) DOMException: An invalid or illegal string was specified
    e https://drive.example.com/media/assets/frontend/static/js/commons.<hash>.js:2
    p https://drive.example.com/media/assets/frontend/static/js/commons.<hash>.js:2
    s https://drive.example.com/media/assets/frontend/static/js/commons.<hash>.js:2
    ...
    88210 https://drive.example.com/media/assets/frontend/static/js/viewFileOnlyoffice.<hash>.js:1
    <anonymous> https://drive.example.com/media/assets/frontend/static/js/viewFileOnlyoffice.<hash>.js:1
commons.<hash>.js:2:1688395

Other (cosmetic) console output observed in the same trace, included for completeness:

Feature Policy: Skipping unsupported feature name "autoplay".         api.js:1300:16
Feature Policy: Skipping unsupported feature name "clipboard-write".  api.js:1300:16
Failed to load 'https://onlyoffice.example.com/9.4.0-<build>/web-apps/apps/common/Analytics.js'.
  A ServiceWorker passed a promise to FetchEvent.respondWith() that rejected with
  'TypeError: NetworkError when attempting to fetch resource.'
unreachable code after return statement   sdk-all-min.js:21477:2
unreachable code after return statement   sdk-all-min.js:55629:54

The Analytics.js NS_ERROR_INTERCEPTION_FAILED is OnlyOffice-side and appears to be a separate, cosmetic issue with their service worker; the editor failure is the DOMException that precedes it.

Editor config delivered by Seahub

Inline var config = {…} block emitted by Seahub on the file-view HTML (JWT signature and user identifiers redacted). The payload is structurally complete and well-formed; the same payload works in Safari/Chrome:

var config = {
  "events": {
    "onRequestReferenceData": onRequestReferenceData,
    "onRequestHistory": onRequestHistory,
    "onRequestHistoryData": onRequestHistoryData,
    "onRequestHistoryClose": onRequestHistoryClose,
  },
  "type": window.screen.width < 992 ? 'mobile' : 'desktop',
  "document": {
    "fileType": "docx",
    "key": "<redacted>",
    "title": "test.docx",
    "url": "https://drive.example.com/seafhttp/files/<token>/test.docx",
    "permissions": { "download": true, "edit": true, "fillForms": true, "copy": true, "print": true, "review": true },
    "referenceData": { "fileKey": "<redacted JWT>", "instanceId": "https://drive.example.com" }
  },
  "documentType": "word",
  "token": "<redacted JWT>",
  "editorConfig": {
    "callbackUrl": "https://drive.example.com/onlyoffice/editor-callback/",
    "lang": "en",
    "mode": "edit",
    "customization": { "forcesave": false, "submitForm": false },
    "user": { "id": "<redacted>", "name": "<redacted>", "image": "https://drive.example.com/media/avatars/default.png" }
  }
};

window.onload = function () {
  docEditor = new DocsAPI.DocEditor("placeholder", config);
};

Minor schema drift (not the cause of this bug, but worth flagging): the JS-side editorConfig.user.image field is encoded as editorConfig.user.avatar_url inside the JWT body. Both fields hold the same string, but the JS object and the JWT payload disagree on the key name.

Possible cause

Between Seafile 12.0 and 13.0, the OnlyOffice file-view entry was migrated from React 17.0.2 to React 18.3.1, and from the legacy ReactDom.render(...) API to createRoot(root).render(...):

- // frontend/src/view-file-onlyoffice.js  (12.0)
- ReactDom.render(<ViewFileOnlyoffice />, document.getElementById('wrapper'));

+ // frontend/src/view-file-onlyoffice.js  (13.0)
+ const root = createRoot(document.getElementById('wrapper'));
+ root.render(<ViewFileOnlyoffice />);

In the same window, frontend/src/components/file-view/file-view.js grew ~55% (6,648 → 10,326 bytes) and now branches on a new documentVendor prop. The most likely culprit is a URL/history-API call inside this component path that runs eagerly under React 18's concurrent root and trips Firefox's stricter argument validation (Firefox is documented to throw InvalidCharacterError for inputs that other engines silently accept).

Seafile 12.0.x (React 17, legacy render API) is reported by the community as still working in Firefox with comparable OnlyOffice versions.

Environment

Value
Seafile CE 13.0.21 (seafileltd/seafile-mc:13.0.21)
OnlyOffice DocumentServer 9.4.0.1 (onlyoffice/documentserver:9.4.0.1)
Reverse proxy Traefik v3, TLS via Cloudflare DNS-01
Browser (broken) Firefox 151.0.1 / Gecko build 20260520211922 / macOS 26.5.0 (Apple Silicon, M4 Pro)
Browsers (working) Safari (macOS 26.5.0); Chrome reported as working by other deployments, not retested by reporter
JWT matching shared secret on both sides; JWT body and signature decoded and verified
Extensions during repro uBlock Origin 1.70.0, 1Password, Bitwarden enabled. The DOMException originates entirely in Seafile's own bundles (commons.<hash>.js and viewFileOnlyoffice.<hash>.js), which extension blocking cannot produce. Clean-profile reproduction can be provided on request.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions