# Error while loading document in Collabora: Invalid URI and WebSocket closed errors

**URL:** <https://forum.collaboraonline.com/t/error-while-loading-document-in-collabora-invalid-uri-and-websocket-closed-errors/3635>\
**Category:** Development\
**Created:** [April 28, 2025, 4:58am UTC](https://forum.collaboraonline.com/t/error-while-loading-document-in-collabora-invalid-uri-and-websocket-closed-errors/3635 "2025-04-28T04:58:30Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Sasidhar3159](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.collaboraonline.com/sasidhar3159/32/1645_2.png) [@Sasidhar3159](https://forum.collaboraonline.com/u/Sasidhar3159)\
**Post date:** [April 28, 2025, 4:58am UTC](https://forum.collaboraonline.com/t/error-while-loading-document-in-collabora-invalid-uri-and-websocket-closed-errors/3635/1 "2025-04-28T04:58:31Z")

</div>

**Title: “Error while loading document in Collabora: Invalid URI and WebSocket closed errors”**

Hi everyone,

I’m trying to integrate Collabora Online (CODE) with a custom backend that implements WOPI APIs.

 ![Screenshot from 2025-04-26 18-48-11](https://europe1.discourse-cdn.com/flex013/uploads/collaboraonline/original/2X/0/0b3004ef315acb390d26f784e8ab811c7b65159f.png)  
I’m running into some issues while trying to load documents inside the iframe.

Here are the important parts of my backend implementation:

```auto
// GET file metadata
collaboraRouter.get('/files/:fileId', async (req, res) => {
  try {
    const { fileId } = req.params;
    const { access_token } = req.query;

    if (!access_token || !ACCESS_TOKENS.has(access_token)) {
      return res.status(401).json({ error: 'Invalid access token' });
    }

    const tokenData = ACCESS_TOKENS.get(access_token);
    if (tokenData.fileId !== fileId) {
      return res.status(403).json({ error: 'Token not valid for this file' });
    }

    const file = bucket.file(`submissions/${fileId}`);
    const [metadata] = await file.getMetadata();

    res.json({
      BaseFileName: fileId,
      Size: parseInt(metadata.size),
      OwnerId: "user1",
      UserId: "user1",
      Version: metadata.generation || '1',
      LastModifiedTime: metadata.updated,
      UserFriendlyName: "User",
      UserCanWrite: true,
      DisablePrint: false,
      DisableExport: false,
      DisableCopy: false,
      HideSaveOption: false,
      PostMessageOrigin: "http://localhost:5173"
    });
  } catch (error) {
    console.error('[WOPI] Error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

// GET file contents
collaboraRouter.get('/files/:fileId/contents', async (req, res) => {
  try {
    const { fileId } = req.params;
    const { access_token } = req.query;

    if (!access_token || !ACCESS_TOKENS.has(access_token)) {
      return res.status(401).json({ error: 'Invalid access token' });
    }

    const file = bucket.file(`submissions/${fileId}`);
    const stream = file.createReadStream();
    stream.pipe(res);
  } catch (error) {
    console.error('[WOPI] Error streaming file:', error);
    res.status(500).json({ error: 'Failed to stream file' });
  }
});

// GET discovery XML
collaboraRouter.get('/hosting/discovery', async (req, res) => {
  try {
    console.log('Fetching discovery.xml from Collabora');
    const response = await axios.get(`${COLLABORA_HOST}/hosting/discovery`);
    res.set('Content-Type', 'application/xml');
    res.send(response.data);
  } catch (error) {
    console.error('Error getting discovery XML:', error);
    res.status(500).json({ error: 'Failed to get discovery XML' });
  }
});
// GET file metadata
collaboraRouter.get('/files/:fileId', async (req, res) => {
  try {
    const { fileId } = req.params;
    const { access_token } = req.query;

    if (!access_token || !ACCESS_TOKENS.has(access_token)) {
      return res.status(401).json({ error: 'Invalid access token' });
    }

    const tokenData = ACCESS_TOKENS.get(access_token);
    if (tokenData.fileId !== fileId) {
      return res.status(403).json({ error: 'Token not valid for this file' });
    }

    const file = bucket.file(`submissions/${fileId}`);
    const [metadata] = await file.getMetadata();

    res.json({
      BaseFileName: fileId,
      Size: parseInt(metadata.size),
      OwnerId: "user1",
      UserId: "user1",
      Version: metadata.generation || '1',
      LastModifiedTime: metadata.updated,
      UserFriendlyName: "User",
      UserCanWrite: true,
      DisablePrint: false,
      DisableExport: false,
      DisableCopy: false,
      HideSaveOption: false,
      PostMessageOrigin: "http://localhost:5173"
    });
  } catch (error) {
    console.error('[WOPI] Error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

// GET file contents
collaboraRouter.get('/files/:fileId/contents', async (req, res) => {
  try {
    const { fileId } = req.params;
    const { access_token } = req.query;

    if (!access_token || !ACCESS_TOKENS.has(access_token)) {
      return res.status(401).json({ error: 'Invalid access token' });
    }

    const file = bucket.file(`submissions/${fileId}`);
    const stream = file.createReadStream();
    stream.pipe(res);
  } catch (error) {
    console.error('[WOPI] Error streaming file:', error);
    res.status(500).json({ error: 'Failed to stream file' });
  }
});

// GET discovery XML
collaboraRouter.get('/hosting/discovery', async (req, res) => {
  try {
    console.log('Fetching discovery.xml from Collabora');
    const response = await axios.get(`${COLLABORA_HOST}/hosting/discovery`);
    res.set('Content-Type', 'application/xml');
    res.send(response.data);
  } catch (error) {
    console.error('Error getting discovery XML:', error);
    res.status(500).json({ error: 'Failed to get discovery XML' });
  }
});

```

**Frontend Console Logs:**

Loading document with fileId: temp.docx  
WOPI source URL: [http://localhost:8080/api/wopi/files/temp.docx](http://localhost:8080/api/wopi/files/temp.docx)  
Found action URL: [http://localhost:9980/browser/.../cool.html](http://localhost:9980/browser/.../cool.html)?  
Final iframe URL: [http://localhost:9980/browser/.../cool.html?WOPISrc=http%3A%2F%2Flocalhost%3A8080%2Fapi%2Fwopi%2Ffiles%2Ftemp.docx&access\_token=](http://localhost:9980/browser/.../cool.html?WOPISrc=http%3A%2F%2Flocalhost%3A8080%2Fapi%2Fwopi%2Ffiles%2Ftemp.docx&access_token=)\*\*\*\*\*\*

When the iframe tries to load, I get WebSocket connection errors:

WebSocket connection to ‘ws://localhost:9980/cool/http%3A%2F%2Flocalhost%3A8080%2Fapi%2Fwopi%2Ffiles%2Ftemp.docx%3Faccess\_token%3D\*\*\*\*\*\*\_ttl%3D0%26permission%3Dedit/ws?WOPISrc=http%3A%2F%2Flocalhost%3A8080%2Fapi%2Fwopi%2Ffiles%2Ftemp.docx&compat=/ws’ failed: WebSocket is closed before the connection is established.

**Collabora Server (Docker) Logs:**

wsd-00001-00031 2025-04-23 16:48:11.844812 +0000 [websrv\_poll] ERR #42: Error while handling Client WS Request: Invalid URI.| wsd/ClientRequestDispatcher.cpp:2259  
wsd-00001-00031 2025-04-23 16:48:12.205977 +0000 [websrv\_poll] ERR #43: Error while handling Client WS Request: Invalid URI.| wsd/ClientRequestDispatcher.cpp:2259

**Summary:**

- Discovery XML is fetched successfully.
- File metadata and file contents API endpoints seem to respond properly when tested individually.
- iframe URL is constructed and loaded, but WebSocket connections are failing.
- Docker container logs show `Invalid URI` errors.
- Testing locally on `localhost`, Collabora server is at `localhost:9980`, backend API is at `localhost:8080`.

* * *

**Environment Details:**

- Backend: Node.js with Express
- Collabora CODE: Docker image (latest)
- Frontend: React
- Running everything on local environment (localhost)

 ![Screenshot from 2025-04-26 18-47-56](https://europe1.discourse-cdn.com/flex013/uploads/collaboraonline/original/2X/2/2b26b85ec8886f4eead0180a0f9db401a754d2f7.png)

---

<div class="post-metadata">

**Author:** ![darshan](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.collaboraonline.com/darshan/32/2230_2.png) [@darshan](https://forum.collaboraonline.com/u/darshan)\
**Post date:** [April 28, 2025, 11:29am UTC](https://forum.collaboraonline.com/t/error-while-loading-document-in-collabora-invalid-uri-and-websocket-closed-errors/3635/2 "2025-04-28T11:29:24Z")

</div>

Hii @Sasidhar3159 Welcome to collabora online forums

In your iframe URL, you’re URL-encoding `WOPISrc`, but **Collabora expects the WebSocket path to remain properly decoded** inside the WebSocket upgrade request.

**Specifically:**  
You’re passing:

```auto
WOPISrc=http%3A%2F%2Flocalhost%3A8080%2Fapi%2Fwopi%2Ffiles%2Ftemp.docx

```

…but the WebSocket URL ends up like:

```auto
ws://localhost:9980/cool/http%3A%2F%2Flocalhost%3A8080%2Fapi%2Fwopi%2Ffiles%2Ftemp.docx...

```

and **Collabora’s WebSocket handler expects a path like** :

```auto
ws://localhost:9980/cool/http://localhost:8080/api/wopi/files/temp.docx...

```

(not URL-encoded inside the `/cool/...` part).

* * *

**Why?**

- When you access `/browser/cool.html?...`, you can URL-encode parameters.
- But for **WebSocket connections** , the path (after `/cool/`) must be **not encoded** , or else Collabora’s `ClientRequestDispatcher` can’t parse it correctly.
- If it sees `%3A`, `%2F`, etc., it says **“Invalid URI”** — exactly the error you see.

**Make sure** the iframe `src` is _constructed correctly_, so that the part **after `/cool/` is decoded**.

The general flow is:

1. Browser loads:

```auto
http://localhost:9980/browser/....cool.html?WOPISrc=encoded_url&access_token=xxx

```

_Here, URL-encoding the `WOPISrc` is fine._

1. Inside cool.html, when Collabora sets up the WebSocket, it tries to connect to:

```auto
ws://localhost:9980/cool/WOPISrc_path_and_query/ws

```

_At this point, if `WOPISrc` was encoded in the wrong way, it breaks._

* * *

Thanks  
Darshan

---

<div class="post-metadata">

**Author:** ![darshan](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.collaboraonline.com/darshan/32/2230_2.png) [@darshan](https://forum.collaboraonline.com/u/darshan)\
**Post date:** [May 1, 2025, 9:01am UTC](https://forum.collaboraonline.com/t/error-while-loading-document-in-collabora-invalid-uri-and-websocket-closed-errors/3635/3 "2025-05-01T09:01:39Z")

</div>


