[Bug]: PayloadTooLargeError (HTTP 413) when syncing mobile local sessions to server #3041

Open
opened 2026-04-25 00:13:13 +02:00 by adam · 9 comments
Owner

Originally created by @Salvoxia on GitHub (Oct 18, 2025).

What happened?

After listening on the Android application without having a server connection for a while (not as in "a prolonged period of time" but "start and stop listening many times"), the next time the Android App establishes connection to server the listening progress made since the last connection is not synced.

What did you expect to happen?

The server should be able to handler a large amount of local sessions for syncing progress.
In any case, if the threshold for reporting local session payload size is exceeded (whatever that might be at the moment), the only way of getting it working again seems to clear the app's cache. Any listening progress made will not be synced to the server and thus is lost.

Steps to reproduce the issue

  1. Disconnect the mobile app from the server
  2. Accumulate sufficient local sessions on the mobile app (my POST payload accumulated to 266kb of JSON)
  3. Reconnect the mobile app to the server
  4. Watch the App and Server logs for HTTP 413 error

It might be more feasible to generate bogus listening sessions for any existing audiobook and manually calling the /api/session/local-all server API endpoint.
Maybe the stack trace in the server logs is already enough to pinpoint where a (rather small) limit in payload size is configured in the server (or configuring a larger limit is missing)?

Audiobookshelf version

v2.30.0

How are you running audiobookshelf?

Docker

What OS is your Audiobookshelf server hosted from?

Linux

If the issue is being seen in the UI, what browsers are you seeing the problem on?

None

Logs

Android App:

INFO
sendSyncLocalSessions: Sending 87 saved local playback sessions to server (https://[SERVER_ADDRESS] (user))
ERROR
sendSyncLocalSessions: Failed to sync local sessions. (Unexpected code response{protocol=h2, code=413, message=, url=https://[SERVER_ADDRESS]}


Server:
18.10.2025 @ 10:28:04	PayloadTooLargeError: request entity too large
18.10.2025 @ 10:28:04	    at readStream (/app/node_modules/raw-body/index.js:156:17)
18.10.2025 @ 10:28:04	    at getRawBody (/app/node_modules/raw-body/index.js:109:12)
18.10.2025 @ 10:28:04	    at read (/app/node_modules/body-parser/lib/read.js:79:3)
18.10.2025 @ 10:28:04	    at jsonParser (/app/node_modules/body-parser/lib/types/json.js:135:5)
18.10.2025 @ 10:28:04	    at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
18.10.2025 @ 10:28:04	    at trim_prefix (/app/node_modules/express/lib/router/index.js:328:13)
18.10.2025 @ 10:28:04	    at /app/node_modules/express/lib/router/index.js:286:9
18.10.2025 @ 10:28:04	    at Function.process_params (/app/node_modules/express/lib/router/index.js:346:12)
18.10.2025 @ 10:28:04	    at next (/app/node_modules/express/lib/router/index.js:280:10)
18.10.2025 @ 10:28:04	    at urlencodedParser (/app/node_modules/body-parser/lib/types/urlencoded.js:100:7)

Additional Notes

No response

Originally created by @Salvoxia on GitHub (Oct 18, 2025). ### What happened? After listening on the Android application without having a server connection for a while (not as in "a prolonged period of time" but "start and stop listening many times"), the next time the Android App establishes connection to server the listening progress made since the last connection is not synced. ### What did you expect to happen? The server should be able to handler a large amount of local sessions for syncing progress. In any case, if the threshold for reporting local session payload size is exceeded (whatever that might be at the moment), the only way of getting it working again seems to clear the app's cache. Any listening progress made will not be synced to the server and thus is lost. ### Steps to reproduce the issue 1. Disconnect the mobile app from the server 2. Accumulate sufficient local sessions on the mobile app (my POST payload accumulated to 266kb of JSON) 3. Reconnect the mobile app to the server 4. Watch the App and Server logs for HTTP 413 error It might be more feasible to generate bogus listening sessions for any existing audiobook and manually calling the `/api/session/local-all` server API endpoint. Maybe the stack trace in the server logs is already enough to pinpoint where a (rather small) limit in payload size is configured in the server (or configuring a larger limit is missing)? ### Audiobookshelf version v2.30.0 ### How are you running audiobookshelf? Docker ### What OS is your Audiobookshelf server hosted from? Linux ### If the issue is being seen in the UI, what browsers are you seeing the problem on? None ### Logs ```shell Android App: INFO sendSyncLocalSessions: Sending 87 saved local playback sessions to server (https://[SERVER_ADDRESS] (user)) ERROR sendSyncLocalSessions: Failed to sync local sessions. (Unexpected code response{protocol=h2, code=413, message=, url=https://[SERVER_ADDRESS]} Server: 18.10.2025 @ 10:28:04 PayloadTooLargeError: request entity too large 18.10.2025 @ 10:28:04 at readStream (/app/node_modules/raw-body/index.js:156:17) 18.10.2025 @ 10:28:04 at getRawBody (/app/node_modules/raw-body/index.js:109:12) 18.10.2025 @ 10:28:04 at read (/app/node_modules/body-parser/lib/read.js:79:3) 18.10.2025 @ 10:28:04 at jsonParser (/app/node_modules/body-parser/lib/types/json.js:135:5) 18.10.2025 @ 10:28:04 at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5) 18.10.2025 @ 10:28:04 at trim_prefix (/app/node_modules/express/lib/router/index.js:328:13) 18.10.2025 @ 10:28:04 at /app/node_modules/express/lib/router/index.js:286:9 18.10.2025 @ 10:28:04 at Function.process_params (/app/node_modules/express/lib/router/index.js:346:12) 18.10.2025 @ 10:28:04 at next (/app/node_modules/express/lib/router/index.js:280:10) 18.10.2025 @ 10:28:04 at urlencodedParser (/app/node_modules/body-parser/lib/types/urlencoded.js:100:7) ``` ### Additional Notes _No response_
adam added the bug label 2026-04-25 00:13:13 +02:00
Author
Owner

@Vito0912 commented on GitHub (Oct 18, 2025):

This is your RP not ABS afaik.
Please increase the payload size in your reverse proxy

I used this endpoint myself to sync thousands of sessions. ABS does not impose a limit

Edit: Even though you see the error in the ABS logs in the past it always was the RP

@Vito0912 commented on GitHub (Oct 18, 2025): This is your RP not ABS afaik. Please increase the payload size in your reverse proxy I used this endpoint myself to sync thousands of sessions. ABS does not impose a limit Edit: Even though you see the error in the ABS logs in the past it always was the RP
Author
Owner

@Salvoxia commented on GitHub (Oct 18, 2025):

@Vito0912 Thanks for your quick reply. We touched the topic briefly before in #1668.

Edit: Even though you see the error in the ABS logs in the past it always was the RP

I don't suppose you could explain why

  • the ABS container logs that stack trace
  • I am able to capture all TCP packets of the HTTP POST request containing my listening history from within the ABS container with tcpdump
  • I am able to upload an 800MB audiobook file hitting the /api/upload endpoint through the same RP with no problems

All of this implies for me that the reverse proxy is not the culprit. Otherwise I have to seriously doubt everything I believe to know about how networking and Docker works (which I might have to).

I'm using traefik as reverse proxy. According to traefik docs, you must explicitly use a buffering middleware to enforce size limits on requests forwarded to applications behind the RP, which I am not using.

Do you have any suggestions what else I could try to rule out it's one thing or the other?

@Salvoxia commented on GitHub (Oct 18, 2025): @Vito0912 Thanks for your quick reply. We touched the topic briefly before in [#1668](https://github.com/advplyr/audiobookshelf-app/issues/1668). >Edit: Even though you see the error in the ABS logs in the past it always was the RP I don't suppose you could explain why - the ABS container logs that stack trace - I am able to capture all TCP packets of the HTTP POST request containing my listening history from within the ABS container with `tcpdump` - I am able to upload an 800MB audiobook file hitting the `/api/upload` endpoint through the same RP with no problems All of this implies for me that the reverse proxy is not the culprit. Otherwise I have to seriously doubt everything I believe to know about how networking and Docker works (which I might have to). I'm using traefik as reverse proxy. According to traefik docs, you must explicitly use a buffering middleware to enforce size limits on requests forwarded to applications behind the RP, which I am not using. Do you have any suggestions what else I could try to rule out it's one thing or the other?
Author
Owner

@Vito0912 commented on GitHub (Oct 18, 2025):

Ah sorry! Totally my bad. I thought your issue was resolved by increasing the limit. I mixed things up!

But it's still very odd. You can see this code of my toolbox: https://github.com/Vito0912/absToolbox/blob/main/web/src/tools/migrateServer.ts#L283C1-L289C12

It uses the local-all endpoint and in my testing I migrated ~3500 sessions of my user. I have no exact since, but it should be way about the 270kb.

But I agree with you that it does not make any sense. Please give me a second to check the code.

@Vito0912 commented on GitHub (Oct 18, 2025): Ah sorry! Totally my bad. I thought your issue *was* resolved by increasing the limit. I mixed things up! But it's still very odd. You can see this code of my toolbox: https://github.com/Vito0912/absToolbox/blob/main/web/src/tools/migrateServer.ts#L283C1-L289C12 It uses the local-all endpoint and in my testing I migrated ~3500 sessions of my user. I have no exact since, but it should be way about the 270kb. But I agree with you that it does not make any sense. Please give me a second to check the code.
Author
Owner

@Vito0912 commented on GitHub (Oct 18, 2025):

ABS seems to set a limit of 10mb for JSON.

I also just tested by sending 10mb of payload and ideed it did not work. I assume this is to prevent (D)DOS. But 10MB should be plenty of sessions (My 3500 are around 5MB) - So near the limit

* h2h3 [content-length: 5473364]
< HTTP/2 200 < server: openresty

Note

I did not actually try to update/add sessions. I just send a lorem ipsum to the endpoint. So there might be the option that, if a single session is to big, it still fails

The only thing I can imagine, is that one of the books in your sessions is gigantic. Something like thousand of tracks and chapters. Then I could see how something like this might happen.

Do you have a book with many files and/or chapters?

@Vito0912 commented on GitHub (Oct 18, 2025): ABS seems to set a limit of 10mb for JSON. I also just tested by sending 10mb of payload and ideed it did not work. I assume this is to prevent (D)DOS. But 10MB should be plenty of sessions (My 3500 are around 5MB) - So near the limit `* h2h3 [content-length: 5473364]` `< HTTP/2 200 < server: openresty` > [!NOTE] > I did not actually try to update/add sessions. I just send a lorem ipsum to the endpoint. So there might be the option that, if a single session is to big, it still fails The only thing I can imagine, is that one of the books in your sessions is gigantic. Something like thousand of tracks and chapters. Then I could see how something like this might happen. Do you have a book with many files and/or chapters?
Author
Owner

@Salvoxia commented on GitHub (Oct 18, 2025):

Hm. not sure I follow here.
Yes, there is one book for which an offline session should be synced that has ~1600 chapters with a run time of 98 hours. But how would that affect syncing sessions if it's not thousands of sessions for that very long book?

@Salvoxia commented on GitHub (Oct 18, 2025): Hm. not sure I follow here. Yes, there is one book for which an offline session should be synced that has ~1600 chapters with a run time of 98 hours. But how would that affect syncing sessions if it's not thousands of sessions for that very long book?
Author
Owner

@Vito0912 commented on GitHub (Oct 18, 2025):

I came across some comment that the internal json parser only allows 100kb of data by default. So that made me think to believe that if one session independent is bigger than 100kb, that it could trigger such behaviour.

But I am not sure if that parser is even used in ABS, but it would make sense to me ATM, as this would be the only different variable then from my setup.
I will look into it tomorrow

@Vito0912 commented on GitHub (Oct 18, 2025): I came across some comment that the internal json parser only allows 100kb of data by default. So that made me think to believe that if one session independent is bigger than 100kb, that it could trigger such behaviour. But I am not sure if that parser is even used in ABS, but it would make sense to me ATM, as this would be the only different variable then from my setup. I will look into it tomorrow
Author
Owner

@jpeel commented on GitHub (Oct 23, 2025):

I think that Vito0912 is correct. The server is using express which defaults to 100kb for json unless the limit is overridden, but it is only overridden for internal-api routes using:

router.use(/^(?!\/internal-api).*/, express.json({ limit: '10mb' }))

in server/Server.js. The limits on other routes need to be increased as well I think for json to fix this.

@jpeel commented on GitHub (Oct 23, 2025): I think that Vito0912 is correct. The server is using express which defaults to 100kb for json unless the limit is overridden, but it is only overridden for internal-api routes using: ``` router.use(/^(?!\/internal-api).*/, express.json({ limit: '10mb' })) ``` in server/Server.js. The limits on other routes need to be increased as well I think for json to fix this.
Author
Owner

@Vito0912 commented on GitHub (Oct 23, 2025):

I also saw that, yet as I said, I was able to send a JSON payload that was 5mb big.
I am not even sure what the internal API is used for, but I am not really into express either.

@Vito0912 commented on GitHub (Oct 23, 2025): I also saw that, yet as I said, I was able to send a JSON payload that was 5mb big. I am not even sure what the internal API is used for, but I am not really into express either.
Author
Owner

@jpeel commented on GitHub (Oct 23, 2025):

Yes, quite right, there is also this set in Server.js:

router.use(express.urlencoded({ extended: true, limit: '5mb' }))

and the error includes at urlencodedParser so I'm assuming that it is exceeding this 5 MB limit when the JSON is url-encoded.

@jpeel commented on GitHub (Oct 23, 2025): Yes, quite right, there is also this set in Server.js: ``` router.use(express.urlencoded({ extended: true, limit: '5mb' })) ``` and the error includes `at urlencodedParser` so I'm assuming that it is exceeding this 5 MB limit when the JSON is url-encoded.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/audiobookshelf#3041