[GH-ISSUE #56] SharePoint connector: file listing works, but file download fails on Graph :/content with 302 Found redirect #39

Open
opened 2026-10-18 21:13:43 +00:00 by bsakaguchi · 4 comments
Owner

Originally created by @schweitzert on GitHub (Jun 17, 2026).
Original GitHub issue: https://github.com/open-webui/oikb/issues/56

Environment

  • oikb version: 0.3.6
  • Deployment: Docker / Portainer
  • Open WebUI version: 0.9.6+
  • Connector: SharePoint
  • Auth: app-only via client secret
  • Microsoft Graph permissions: Sites.Read.All (Application), admin consent granted
  • SharePoint library: Dokumente

Summary

The SharePoint connector can successfully:

  • authenticate against Microsoft Entra
  • resolve the SharePoint site
  • list drives/libraries
  • list folders
  • detect files
  • create directories in the target Open WebUI Knowledge Base

However, the actual file content download fails when requesting:

GET /drives/{drive-id}/root:/path/to/file:/content

Microsoft Graph responds with:

302 Found

redirecting to a SharePoint download.aspx URL, and oikb treats this as an error instead of following the redirect and downloading the file.

As a result:

  • the folder structure is created in the KB
  • but no file contents are uploaded

Config

sources:
  - name: sp-test
    source: sharepoint:tenant.sharepoint.com/Dokumente
    kb-id: <kb-id>
    interval: 1h
    filter:
      include:
        - "Test/**"

What works

These steps succeed:

  1. Token request to Entra:

    • POST https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token
    • returns 200 OK
  2. Site lookup works

    • GET https://graph.microsoft.com/v1.0/sites/tenant.sharepoint.com
    • returns 200 OK
  3. Drive lookup works

    • GET https://graph.microsoft.com/v1.0/sites/{site-id}/drives
    • returns 200 OK
  4. Folder listing:

    • GET https://graph.microsoft.com/v1.0/drives/{drive-id}/root:/Test:/children
    • returns 200 OK
  5. Open WebUI diff + directory creation:

    • POST /api/v1/knowledge/<kb-id>/sync/diff -> 200 OK
    • POST /api/v1/knowledge/<kb-id>/dirs/create -> 200 OK

So the connector clearly sees the folder and its files.

Actual failure

When oikb tries to fetch file content, e.g.:

GET https://graph.microsoft.com/v1.0/drives/{drive-id}/root:/Test/example.txt:/content

the response is:

HTTP/1.1 302 Found

with a redirect location like:

https://tenant.sharepoint.com/_layouts/15/download.aspx?UniqueId=...&tempauth=...&ApiVersion=2.0

oikb then logs this as an error and skips the file.

Relevant log excerpt

INFO ts=<timestamp> logger=httpx msg=HTTP Request: POST https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token "HTTP/1.1 200 OK"
INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/sites/tenant.sharepoint.com "HTTP/1.1 200 OK"
INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/sites/{site-id}/drives "HTTP/1.1 200 OK"
INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root/children "HTTP/1.1 200 OK"
INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Test:/children "HTTP/1.1 200 OK"
INFO ts=<timestamp> logger=httpx msg=HTTP Request: POST http://openwebui:8080/api/v1/knowledge/<kb-id>/sync/diff "HTTP/1.1 200 OK"
INFO ts=<timestamp> logger=httpx msg=HTTP Request: POST http://openwebui:8080/api/v1/knowledge/<kb-id>/dirs/create "HTTP/1.1 200 OK"
INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Test/example.txt:/content "HTTP/1.1 302 Found"

✗ Test/example.txt: Redirect response '302 Found' for url 'https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Test/example.txt:/content'
Redirect location: 'https://tenant.sharepoint.com/_layouts/15/download.aspx?UniqueId=...&tempauth=...&ApiVersion=2.0'

INFO ts=<timestamp> logger=oikb.daemon msg=Synced sharepoint:tenant.sharepoint.com/Dokumente -> <kb-id>: 1 dirs created (1008ms)

Expected behavior

When Graph returns 302 Found for a :/content request, the connector should follow the redirect (or otherwise retrieve the file content from the redirected URL) and upload the file into the Knowledge Base.

Actual behavior

  • folder is created in KB
  • file is detected
  • file content is not uploaded
  • connector stops at the redirect response
Originally created by @schweitzert on GitHub (Jun 17, 2026). Original GitHub issue: https://github.com/open-webui/oikb/issues/56 ### Environment - **oikb version:** 0.3.6 - **Deployment:** Docker / Portainer - **Open WebUI version:** 0.9.6+ - **Connector:** SharePoint - **Auth:** app-only via **client secret** - **Microsoft Graph permissions:** `Sites.Read.All` (Application), admin consent granted - **SharePoint library:** `Dokumente` --- ### Summary The SharePoint connector can successfully: - authenticate against Microsoft Entra - resolve the SharePoint site - list drives/libraries - list folders - detect files - create directories in the target Open WebUI Knowledge Base However, the actual file content download fails when requesting: `GET /drives/{drive-id}/root:/path/to/file:/content` Microsoft Graph responds with: `302 Found` redirecting to a SharePoint `download.aspx` URL, and oikb treats this as an error instead of following the redirect and downloading the file. As a result: - the folder structure is created in the KB - but **no file contents are uploaded** --- ### Config ```yaml sources: - name: sp-test source: sharepoint:tenant.sharepoint.com/Dokumente kb-id: <kb-id> interval: 1h filter: include: - "Test/**" ``` ### What works These steps succeed: 1. Token request to Entra: - `POST https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token` - returns `200 OK` 2. Site lookup works - `GET https://graph.microsoft.com/v1.0/sites/tenant.sharepoint.com` - returns `200 OK` 3. Drive lookup works - `GET https://graph.microsoft.com/v1.0/sites/{site-id}/drives` - returns `200 OK` 4. Folder listing: - `GET https://graph.microsoft.com/v1.0/drives/{drive-id}/root:/Test:/children` - returns `200 OK` 5. Open WebUI diff + directory creation: - `POST /api/v1/knowledge/<kb-id>/sync/diff` -> `200 OK` - `POST /api/v1/knowledge/<kb-id>/dirs/create` -> `200 OK` So the connector clearly sees the folder and its files. ### Actual failure When oikb tries to fetch file content, e.g.: `GET https://graph.microsoft.com/v1.0/drives/{drive-id}/root:/Test/example.txt:/content` the response is: `HTTP/1.1 302 Found` with a redirect location like: `https://tenant.sharepoint.com/_layouts/15/download.aspx?UniqueId=...&tempauth=...&ApiVersion=2.0` oikb then logs this as an error and skips the file. ### Relevant log excerpt ```text INFO ts=<timestamp> logger=httpx msg=HTTP Request: POST https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token "HTTP/1.1 200 OK" INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/sites/tenant.sharepoint.com "HTTP/1.1 200 OK" INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/sites/{site-id}/drives "HTTP/1.1 200 OK" INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root/children "HTTP/1.1 200 OK" INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Test:/children "HTTP/1.1 200 OK" INFO ts=<timestamp> logger=httpx msg=HTTP Request: POST http://openwebui:8080/api/v1/knowledge/<kb-id>/sync/diff "HTTP/1.1 200 OK" INFO ts=<timestamp> logger=httpx msg=HTTP Request: POST http://openwebui:8080/api/v1/knowledge/<kb-id>/dirs/create "HTTP/1.1 200 OK" INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Test/example.txt:/content "HTTP/1.1 302 Found" ✗ Test/example.txt: Redirect response '302 Found' for url 'https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Test/example.txt:/content' Redirect location: 'https://tenant.sharepoint.com/_layouts/15/download.aspx?UniqueId=...&tempauth=...&ApiVersion=2.0' INFO ts=<timestamp> logger=oikb.daemon msg=Synced sharepoint:tenant.sharepoint.com/Dokumente -> <kb-id>: 1 dirs created (1008ms) ``` ### Expected behavior When Graph returns `302 Found` for a `:/content` request, the connector should follow the redirect (or otherwise retrieve the file content from the redirected URL) and upload the file into the Knowledge Base. ### Actual behavior - folder is created in KB - file is detected - file content is not uploaded - connector stops at the redirect response
Author
Owner

@Tron138 commented on GitHub (Jun 17, 2026):

When trying to download a file from SharePoint via the Microsoft Graph API, Microsoft does not return the file payload immediately. Instead, it responds with an HTTP 302 Redirect, pointing to a secure, temporary download URL (the redirect location).

The Problem:
The Python library (httpx) used by oikb for web requests is configured by default to ignore redirects. Consequently, the execution stops at the 302 Found status code instead of following the link to actually download the file.

The Solution: Applying the Redirect Fix
We can apply a quick patch directly inside the running Docker container to instruct oikb to automatically follow these download redirects.

Run the following command in your terminal to patch the code inside the container:

Bash
docker exec -it oikb-sync python -c "
import oikb.connectors.sharepoint as s
path = s.file
with open(path, 'r') as f:
code = f.read()
code = code.replace('timeout=60.0,', 'timeout=60.0,\n follow_redirects=True,')
with open(path, 'w') as f:
f.write(code)
print('--- Redirect fix successfully applied! ---')
"

<!-- gh-comment-id:4734455302 --> @Tron138 commented on GitHub (Jun 17, 2026): When trying to download a file from SharePoint via the Microsoft Graph API, Microsoft does not return the file payload immediately. Instead, it responds with an HTTP 302 Redirect, pointing to a secure, temporary download URL (the redirect location). The Problem: The Python library (httpx) used by oikb for web requests is configured by default to ignore redirects. Consequently, the execution stops at the 302 Found status code instead of following the link to actually download the file. The Solution: Applying the Redirect Fix We can apply a quick patch directly inside the running Docker container to instruct oikb to automatically follow these download redirects. Run the following command in your terminal to patch the code inside the container: Bash docker exec -it oikb-sync python -c " import oikb.connectors.sharepoint as s path = s.__file__ with open(path, 'r') as f: code = f.read() code = code.replace('timeout=60.0,', 'timeout=60.0,\n follow_redirects=True,') with open(path, 'w') as f: f.write(code) print('--- Redirect fix successfully applied! ---') "
Author
Owner

@Tch1b0 commented on GitHub (Jun 17, 2026):

Just like @Tron138 described, this seems to be fixed by adding a follow_redirects=True parameter here.

<!-- gh-comment-id:4734493524 --> @Tch1b0 commented on GitHub (Jun 17, 2026): Just like @Tron138 described, this seems to be fixed by adding a `follow_redirects=True` parameter [here](https://github.com/open-webui/oikb/blob/443304642beaebd4f15ca1ce962c871c1f25107e/src/oikb/connectors/sharepoint.py#L85).
Author
Owner

@Tron138 commented on GitHub (Jun 17, 2026):

and if you want to make the sharepoint url like this: sharepoint.com/sites/one/AllForAi
so it only searches the folder AllForAi and subfolder. you can replace the parts = source.split("/", 1) with parts = source.rsplit("/", 1).

here is the docker quick fix,

docker exec -it <CONTAINER_NAME> python -c "
import oikb.connectors.sharepoint as s
path = s.file
with open(path, 'r') as f:
code = f.read()
code = code.replace('source.split("/", 1)', 'source.rsplit("/", 1)')
with open(path, 'w') as f:
f.write(code)
print('--- Code erfolgreich ---')
"

but then you need to make everything in the .oikb.yaml in " " like:
sources:

  • name: Sharepoint
    source: "sharepoint.com:/sites/one/Ai"
    kb-id: "YOUR CODE"
    interval: "1h"
<!-- gh-comment-id:4734503702 --> @Tron138 commented on GitHub (Jun 17, 2026): and if you want to make the sharepoint url like this: sharepoint.com/sites/one/AllForAi so it only searches the folder AllForAi and subfolder. you can replace the parts = source.split("/", 1) with parts = source.rsplit("/", 1). here is the docker quick fix, docker exec -it <CONTAINER_NAME> python -c " import oikb.connectors.sharepoint as s path = s.__file__ with open(path, 'r') as f: code = f.read() code = code.replace('source.split(\"/\", 1)', 'source.rsplit(\"/\", 1)') with open(path, 'w') as f: f.write(code) print('--- Code erfolgreich ---') " but then you need to make everything in the .oikb.yaml in " " like: sources: - name: Sharepoint source: "sharepoint.com:/sites/one/Ai" kb-id: "YOUR CODE" interval: "1h"
Author
Owner

@schweitzert commented on GitHub (Jun 18, 2026):

Quick update from my side:

Both workaround fixes are working for me now:

  1. Redirect fix
    Adding follow_redirects=True fixes the SharePoint file download problem when Microsoft Graph returns 302 Found for :/content.

  2. Site path parsing fix
    Replacing source.split("/", 1) with source.rsplit("/", 1) works together with a source format like:

source: "sharepoint:tenant.sharepoint.com:/sites/team-site/Dokumente"

This allows syncing from a SharePoint site-based library instead of only the root-level library.

For example, this works for me now:

sources:
  - name: sharepoint-site-test
    source: "sharepoint:tenant.sharepoint.com:/sites/team-site/Dokumente"
    kb-id: "<kb-id>"
    interval: "30m"
    filter:
      include:
        - "Test/**"

And the sanitized logs now show the redirect being followed successfully and the file uploaded to Open WebUI:


INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Test/example.txt:/content "HTTP/1.1 302 Found"
INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://tenant.sharepoint.com/_layouts/15/download.aspx?UniqueId=...&tempauth=...&ApiVersion=2.0 "HTTP/1.1 200 OK"
INFO ts=<timestamp> logger=httpx msg=HTTP Request: POST http://openwebui:8080/api/v1/files/ "HTTP/1.1 200 OK"
INFO ts=<timestamp> logger=oikb.daemon msg=Synced sharepoint:tenant.sharepoint.com:/sites/team-site/Dokumente -> <kb-id>: 1 added (1168ms)

So from a functional point of view, both fixes solve the main issues on my side.

Questions

  1. Will these fixes be implemented officially?

Right now both changes are applied as quick patches inside the running container, so they are not update-resistant.
Is there already a plan to include these fixes in an official release? And if yes, is there any rough timeline? It would be very helpful to have this supported natively, especially for site-based SharePoint / Teams document libraries.

  1. Is there a way to avoid scanning the full SharePoint structure on every sync?

Even with the working site-based source and a filter like:

filter:
  include:
    - "Test/**"

the connector still appears to recursively scan a very large part of the SharePoint library before applying the filter.

Sanitized example log excerpts:

INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Team-Files/Subfolder-A:/children "HTTP/1.1 200 OK"
INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Team-Files/Subfolder-B:/children "HTTP/1.1 200 OK"
INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Team-Files/Subfolder-C:/children "HTTP/1.1 200 OK"
INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Team-Files/Subfolder-D:/children "HTTP/1.1 200 OK"

This makes syncs relatively slow for large SharePoint sites, because it seems to enumerate a lot of folders every time before the filter limits which files are actually uploaded.

Is there currently any recommended approach to reduce this?

For example:

  • applying the filter earlier during traversal
  • limiting recursion to the included folder
  • using a more specific source path
  • or using Graph delta APIs / incremental folder traversal

This would be especially helpful for Teams-based SharePoint sites with a lot of data, where only a small subfolder should be synced.

Thanks again the current workarounds already helped a lot.

<!-- gh-comment-id:4740319727 --> @schweitzert commented on GitHub (Jun 18, 2026): Quick update from my side: Both workaround fixes are working for me now: 1. **Redirect fix** Adding `follow_redirects=True` fixes the SharePoint file download problem when Microsoft Graph returns `302 Found` for `:/content`. 2. **Site path parsing fix** Replacing `source.split("/", 1)` with `source.rsplit("/", 1)` works together with a source format like: ```yaml source: "sharepoint:tenant.sharepoint.com:/sites/team-site/Dokumente" ``` This allows syncing from a SharePoint site-based library instead of only the root-level library. For example, this works for me now: ```yaml sources: - name: sharepoint-site-test source: "sharepoint:tenant.sharepoint.com:/sites/team-site/Dokumente" kb-id: "<kb-id>" interval: "30m" filter: include: - "Test/**" ``` And the sanitized logs now show the redirect being followed successfully and the file uploaded to Open WebUI: ```text INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Test/example.txt:/content "HTTP/1.1 302 Found" INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://tenant.sharepoint.com/_layouts/15/download.aspx?UniqueId=...&tempauth=...&ApiVersion=2.0 "HTTP/1.1 200 OK" INFO ts=<timestamp> logger=httpx msg=HTTP Request: POST http://openwebui:8080/api/v1/files/ "HTTP/1.1 200 OK" INFO ts=<timestamp> logger=oikb.daemon msg=Synced sharepoint:tenant.sharepoint.com:/sites/team-site/Dokumente -> <kb-id>: 1 added (1168ms) ``` So from a functional point of view, both fixes solve the main issues on my side. ### Questions 1. **Will these fixes be implemented officially?** Right now both changes are applied as quick patches inside the running container, so they are not update-resistant. Is there already a plan to include these fixes in an official release? And if yes, is there any rough timeline? It would be very helpful to have this supported natively, especially for site-based SharePoint / Teams document libraries. 2. **Is there a way to avoid scanning the full SharePoint structure on every sync?** Even with the working site-based source and a filter like: ```yaml filter: include: - "Test/**" ``` the connector still appears to recursively scan a very large part of the SharePoint library before applying the filter. Sanitized example log excerpts: ```text INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Team-Files/Subfolder-A:/children "HTTP/1.1 200 OK" INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Team-Files/Subfolder-B:/children "HTTP/1.1 200 OK" INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Team-Files/Subfolder-C:/children "HTTP/1.1 200 OK" INFO ts=<timestamp> logger=httpx msg=HTTP Request: GET https://graph.microsoft.com/v1.0/drives/<drive-id>/root:/Team-Files/Subfolder-D:/children "HTTP/1.1 200 OK" ``` This makes syncs relatively slow for large SharePoint sites, because it seems to enumerate a lot of folders every time before the filter limits which files are actually uploaded. Is there currently any recommended approach to reduce this? For example: - applying the filter earlier during traversal - limiting recursion to the included folder - using a more specific source path - or using Graph delta APIs / incremental folder traversal This would be especially helpful for Teams-based SharePoint sites with a lot of data, where only a small subfolder should be synced. Thanks again the current workarounds already helped a lot.
Sign in to join this conversation.
No labels
pull-request
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/oikb#39
No description provided.