[Bug]: Android app will not play or download anything. #1230

Closed
opened 2026-04-24 23:54:25 +02:00 by adam · 15 comments
Owner

Originally created by @SirBisgaard on GitHub (Jun 12, 2025).

I have verified that the bug is not already awaiting release

Yes

What was the Problem?

When I use the app every book and podcast will give me the following error: "Server play request" failed or "server request failed".
No logs, no nothing. Only the red status that the request failed.

I have a OPNsense with Nginx running in between, with HTTPS enabled.
My problem is every other app or browser works with no problems.
It is only the first party app that does not work.

If I connect directly to the server with the app it works.

Steps to Reproduce the Issue

Have OPNsense setup with Nginx and HTTPS.
Use the first party android app with public url
Play or download any media

What was Expected?

I was expecting it to just work. 😃

Phone Model

OnePlus 9 Pro & Google Pixel 9a

Phone OS

Android 15

Audiobookshelf App Version

Android App - 0.9.81

Installation Source

Google Play Store

Additional Notes

I have also created an issue here, but I suspect that the bug is in the app.
https://github.com/advplyr/audiobookshelf/issues/4402

Originally created by @SirBisgaard on GitHub (Jun 12, 2025). ### I have verified that the [bug is not already awaiting release](https://github.com/advplyr/audiobookshelf-app/issues?q=is%3Aissue%20label%3A%22awaiting%20release%22) Yes ### What was the Problem? When I use the app every book and podcast will give me the following error: "Server play request" failed or "server request failed". No logs, no nothing. Only the red status that the request failed. I have a OPNsense with Nginx running in between, with HTTPS enabled. My problem is every other app or browser works with no problems. It is only the first party app that does not work. If I connect directly to the server with the app it works. ### Steps to Reproduce the Issue Have OPNsense setup with Nginx and HTTPS. Use the first party android app with public url Play or download any media ### What was Expected? I was expecting it to just work. 😃 ### Phone Model OnePlus 9 Pro & Google Pixel 9a ### Phone OS Android 15 ### Audiobookshelf App Version Android App - 0.9.81 ### Installation Source Google Play Store ### Additional Notes I have also created an issue here, but I suspect that the bug is in the app. https://github.com/advplyr/audiobookshelf/issues/4402
adam added the bugunable to reproduce labels 2026-04-24 23:54:25 +02:00
adam closed this issue 2026-04-24 23:54:26 +02:00
Author
Owner

@nichwall commented on GitHub (Jun 12, 2025):

Can you share logs from the app?

@nichwall commented on GitHub (Jun 12, 2025): Can you share logs from the app?
Author
Owner

@SirBisgaard commented on GitHub (Jun 12, 2025):

There are no errors produced in the log while using the app. This is from a cleared log and I have only pressed the play button and got the “Server play request failed”:
06/12/2025 21:28:58.547 [INFO] playLibraryItem: Received play request for library item bb24bc45-42cb-473f-89e6-187f92324d9e
06/12/2025 21:28:58.572 [INFO] prepareLibraryItem: lid=bb24bc45-42cb-473f-89e6-187f92324d9e, startTimeOverride=null, playbackRate=1.0

@SirBisgaard commented on GitHub (Jun 12, 2025): There are no errors produced in the log while using the app. This is from a cleared log and I have only pressed the play button and got the “Server play request failed”: 06/12/2025 21:28:58.547 [INFO] playLibraryItem: Received play request for library item bb24bc45-42cb-473f-89e6-187f92324d9e 06/12/2025 21:28:58.572 [INFO] prepareLibraryItem: lid=bb24bc45-42cb-473f-89e6-187f92324d9e, startTimeOverride=null, playbackRate=1.0
Author
Owner

@nichwall commented on GitHub (Jun 12, 2025):

What do the logs say when directly connected by IP?

@nichwall commented on GitHub (Jun 12, 2025): What do the logs say when directly connected by IP?
Author
Owner

@SirBisgaard commented on GitHub (Jun 13, 2025):

I will get the log later for you, but it seems like there are no logging when the error is dropped.
https://github.com/advplyr/audiobookshelf-app/blob/d26403c8004fcc06509d87ec8ad6b31ac7fb7322/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt#L240

Would it make sense to add some more to ensure this issue can be resolved?

@SirBisgaard commented on GitHub (Jun 13, 2025): I will get the log later for you, but it seems like there are no logging when the error is dropped. https://github.com/advplyr/audiobookshelf-app/blob/d26403c8004fcc06509d87ec8ad6b31ac7fb7322/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt#L240 Would it make sense to add some more to ensure this issue can be resolved?
Author
Owner

@nichwall commented on GitHub (Jun 13, 2025):

Would it make sense to add some more to ensure this issue can be resolved?

Yes, user accessible logging was just added in the most recent app release, so they are still pretty limited.

@nichwall commented on GitHub (Jun 13, 2025): > Would it make sense to add some more to ensure this issue can be resolved? Yes, user accessible logging was just added in the most recent app release, so they are still pretty limited.
Author
Owner

@SirBisgaard commented on GitHub (Jun 13, 2025):

Everything starts somewhere. 😄

06/13/2025 19:00:52.598 [INFO] playLibraryItem: Received play request for library item bb24bc45-42cb-473f-89e6-187f92324d9e 
06/13/2025 19:00:52.617 [INFO] prepareLibraryItem: lid=bb24bc45-42cb-473f-89e6-187f92324d9e, startTimeOverride=null, playbackRate=1.0
06/13/2025 19:00:52.897 [INFO] preparePlayer: Started playback session for item bb24bc45-42cb-473f-89e6-187f92324d9e. MediaPlayer exo-player
06/13/2025 19:00:52.904 [INFO] preparePlayer: Direct playing item bb24bc45-42cb-473f-89e6-187f92324d9e.
@SirBisgaard commented on GitHub (Jun 13, 2025): Everything starts somewhere. 😄 ``` 06/13/2025 19:00:52.598 [INFO] playLibraryItem: Received play request for library item bb24bc45-42cb-473f-89e6-187f92324d9e 06/13/2025 19:00:52.617 [INFO] prepareLibraryItem: lid=bb24bc45-42cb-473f-89e6-187f92324d9e, startTimeOverride=null, playbackRate=1.0 06/13/2025 19:00:52.897 [INFO] preparePlayer: Started playback session for item bb24bc45-42cb-473f-89e6-187f92324d9e. MediaPlayer exo-player 06/13/2025 19:00:52.904 [INFO] preparePlayer: Direct playing item bb24bc45-42cb-473f-89e6-187f92324d9e. ```
Author
Owner

@SirBisgaard commented on GitHub (Jun 13, 2025):

Could it make sense to add the following loggin to the ApiHandler @nichwall?

ApiHandler.kt:345

fun playLibraryItem(libraryItemId:String, episodeId:String?, playItemRequestPayload:PlayItemRequestPayload, cb: (PlaybackSession?) -> Unit) {
    val payload = JSObject(jacksonMapper.writeValueAsString(playItemRequestPayload))

    val endpoint = if (episodeId.isNullOrEmpty()) "/api/items/$libraryItemId/play" else "/api/items/$libraryItemId/play/$episodeId"
    postRequest(endpoint, payload, null) {
        if (it.has("error")) {
            Log.e(tag, "playLibraryItem failed: ${it.getString("error")}")
            cb(null)
        } else {
            try {
                it.put("serverConnectionConfigId", DeviceManager.serverConnectionConfig?.id)
                it.put("serverAddress", DeviceManager.serverAddress)
                val playbackSession = jacksonMapper.readValue<PlaybackSession>(it.toString())
                cb(playbackSession)
            } catch (e: Exception) {
                // This will catch JSON parsing/deserialization errors
                Log.e(tag, "Failed to parse PlaybackSession from server response for endpoint: $endpoint", e)
                Log.e(tag, "Mismatched server response body: ${it.toString()}")
                cb(null)
            }
        }
    }
}

And ApiHandler.kt:98

private fun makeRequest(request:Request, httpClient:OkHttpClient?, cb: (JSObject) -> Unit) {
    val client = httpClient ?: defaultClient

    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            // Add the request URL to the log message for context
            Log.e(tag, "Request failed for URL: ${request.url}", e)

            val jsobj = JSObject()
            jsobj.put("error", "Failed to connect to ${request.url.host}. Please check network connection and server address.")
            cb(jsobj)
        }

        override fun onResponse(call: Call, response: Response) {
            response.use {
                val bodyString = it.body?.string() // Read body once and reuse

                if (!it.isSuccessful) {
                    // Log the URL, the HTTP code, and the error body from the server
                    Log.e(tag, "Unsuccessful response for URL: ${request.url}")
                    Log.e(tag, "Response Code: ${it.code}")
                    Log.e(tag, "Response Body: $bodyString")
                    
                    val jsobj = JSObject()
                    // Pass a more useful error message
                    jsobj.put("error", "HTTP Error ${it.code} for ${request.url}. Body: $bodyString")
                    cb(jsobj)
                    return
                }

                if (bodyString.isNullOrEmpty() || bodyString == "OK") {
                    cb(JSObject())
                } else {
                    try {
                        var jsonObj = JSObject()
                        if (bodyString.startsWith("[")) {
                            val array = JSArray(bodyString)
                            jsonObj.put("value", array)
                        } else {
                            jsonObj = JSObject(bodyString)
                        }
                        cb(jsonObj)
                    } catch(je:JSONException) {
                        Log.e(tag, "Invalid JSON in response for URL ${request.url}", je)
                        Log.e(tag, "Invalid JSON Body: $bodyString")
                        val jsobj = JSObject()
                        jsobj.put("error", "Invalid JSON response from server.")
                        cb(jsobj)
                    }
                }
            }
        }
    })
}
@SirBisgaard commented on GitHub (Jun 13, 2025): Could it make sense to add the following loggin to the ApiHandler @nichwall? [ApiHandler.kt:345](https://github.com/advplyr/audiobookshelf-app/blob/d26403c8004fcc06509d87ec8ad6b31ac7fb7322/android/app/src/main/java/com/audiobookshelf/app/server/ApiHandler.kt#L345) ``` kt fun playLibraryItem(libraryItemId:String, episodeId:String?, playItemRequestPayload:PlayItemRequestPayload, cb: (PlaybackSession?) -> Unit) { val payload = JSObject(jacksonMapper.writeValueAsString(playItemRequestPayload)) val endpoint = if (episodeId.isNullOrEmpty()) "/api/items/$libraryItemId/play" else "/api/items/$libraryItemId/play/$episodeId" postRequest(endpoint, payload, null) { if (it.has("error")) { Log.e(tag, "playLibraryItem failed: ${it.getString("error")}") cb(null) } else { try { it.put("serverConnectionConfigId", DeviceManager.serverConnectionConfig?.id) it.put("serverAddress", DeviceManager.serverAddress) val playbackSession = jacksonMapper.readValue<PlaybackSession>(it.toString()) cb(playbackSession) } catch (e: Exception) { // This will catch JSON parsing/deserialization errors Log.e(tag, "Failed to parse PlaybackSession from server response for endpoint: $endpoint", e) Log.e(tag, "Mismatched server response body: ${it.toString()}") cb(null) } } } } ``` And [ApiHandler.kt:98](https://github.com/advplyr/audiobookshelf-app/blob/d26403c8004fcc06509d87ec8ad6b31ac7fb7322/android/app/src/main/java/com/audiobookshelf/app/server/ApiHandler.kt#L98) ``` kt private fun makeRequest(request:Request, httpClient:OkHttpClient?, cb: (JSObject) -> Unit) { val client = httpClient ?: defaultClient client.newCall(request).enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { // Add the request URL to the log message for context Log.e(tag, "Request failed for URL: ${request.url}", e) val jsobj = JSObject() jsobj.put("error", "Failed to connect to ${request.url.host}. Please check network connection and server address.") cb(jsobj) } override fun onResponse(call: Call, response: Response) { response.use { val bodyString = it.body?.string() // Read body once and reuse if (!it.isSuccessful) { // Log the URL, the HTTP code, and the error body from the server Log.e(tag, "Unsuccessful response for URL: ${request.url}") Log.e(tag, "Response Code: ${it.code}") Log.e(tag, "Response Body: $bodyString") val jsobj = JSObject() // Pass a more useful error message jsobj.put("error", "HTTP Error ${it.code} for ${request.url}. Body: $bodyString") cb(jsobj) return } if (bodyString.isNullOrEmpty() || bodyString == "OK") { cb(JSObject()) } else { try { var jsonObj = JSObject() if (bodyString.startsWith("[")) { val array = JSArray(bodyString) jsonObj.put("value", array) } else { jsonObj = JSObject(bodyString) } cb(jsonObj) } catch(je:JSONException) { Log.e(tag, "Invalid JSON in response for URL ${request.url}", je) Log.e(tag, "Invalid JSON Body: $bodyString") val jsobj = JSObject() jsobj.put("error", "Invalid JSON response from server.") cb(jsobj) } } } } }) } ```
Author
Owner

@gingermike commented on GitHub (Jul 22, 2025):

Also seeing this issue with most up to date server and 0.10.0-beta of the app.

I use a reverse proxy into my local network as I'm behind CGNAT.

Same error and flavor of log as above. I've reinstalled the app, but still not working

@gingermike commented on GitHub (Jul 22, 2025): Also seeing this issue with most up to date server and 0.10.0-beta of the app. I use a reverse proxy into my local network as I'm behind CGNAT. Same error and flavor of log as above. I've reinstalled the app, but still not working
Author
Owner

@SirBisgaard commented on GitHub (Jul 22, 2025):

I use a reverse proxy into my local network as I'm behind CGNAT.
There must be somthing with the way network is handled in the app, when every single other app works.

When I have time, I want to run the app locally to find the issue.
The only thing holding me back is all the bloat Android studio comes with. 🥇

@SirBisgaard commented on GitHub (Jul 22, 2025): > I use a reverse proxy into my local network as I'm behind CGNAT. There must be somthing with the way network is handled in the app, when every single other app works. When I have time, I want to run the app locally to find the issue. The only thing holding me back is all the bloat Android studio comes with. 🥇
Author
Owner

@alxgarci commented on GitHub (Jul 23, 2025):

Same problem happening here, nothing plays on Android App. On audiobookshelf (last version, v2.26.2 in docker) the logs say that 'path' sent to reproduce was null.

@alxgarci commented on GitHub (Jul 23, 2025): Same problem happening here, nothing plays on Android App. On audiobookshelf (last version, v2.26.2 in docker) the logs say that 'path' sent to reproduce was null.
Author
Owner

@nichwall commented on GitHub (Jul 23, 2025):

Same problem happening here, nothing plays on Android App. On audiobookshelf (last version, v2.26.2 in docker) the logs say that 'path' sent to reproduce was null.

The path being null is fixed for the next release (new and likely separate issue) https://github.com/advplyr/audiobookshelf-app/issues/1635

@nichwall commented on GitHub (Jul 23, 2025): > Same problem happening here, nothing plays on Android App. On audiobookshelf (last version, v2.26.2 in docker) the logs say that 'path' sent to reproduce was null. The path being `null` is fixed for the next release (new and likely separate issue) https://github.com/advplyr/audiobookshelf-app/issues/1635
Author
Owner

@gingermike commented on GitHub (Jul 24, 2025):

This appears to have mysteriously fixed itself after upgrading to server v2.26.3

@gingermike commented on GitHub (Jul 24, 2025): This appears to have mysteriously fixed itself after upgrading to server v2.26.3
Author
Owner

@zone-zero commented on GitHub (Sep 16, 2025):

I'm having this same issue. When connecting to my k8s cluster via lan (traefik->audiobookshelf 2.29 container) everything works as expected with both the web player and the android player. When connecting over the internet, (cloudflare->nginx->traefik->audiobookshelf 2.29 container) the android player fails to play or download anything. No app logs with errors, just "Server play request failed" banners popping up. No requests are logged by the web server. The web player works as expected.

I'm logging in with authentik, if that matters.

@zone-zero commented on GitHub (Sep 16, 2025): I'm having this same issue. When connecting to my k8s cluster via lan (traefik->audiobookshelf 2.29 container) everything works as expected with both the web player and the android player. When connecting over the internet, (cloudflare->nginx->traefik->audiobookshelf 2.29 container) the android player fails to play or download anything. No app logs with errors, just "Server play request failed" banners popping up. No requests are logged by the web server. The web player works as expected. I'm logging in with authentik, if that matters.
Author
Owner

@zone-zero commented on GitHub (Sep 29, 2025):

I can confirm that switching to HAProxy from Nginx resolved the issue. Definitely something about interactions with Nginx the app does not like.

@zone-zero commented on GitHub (Sep 29, 2025): I can confirm that switching to HAProxy from Nginx resolved the issue. Definitely something about interactions with Nginx the app does not like.
Author
Owner

@SirBisgaard commented on GitHub (Oct 4, 2025):

I switched to HAProxy, and it fixed the issue.

I used the following guide with success.
https://blog.holtzweb.com/posts/opnsense-with-haproxy-and-lets-encrypt/#haproxy-inital-configuration

@SirBisgaard commented on GitHub (Oct 4, 2025): I switched to HAProxy, and it fixed the issue. I used the following guide with success. https://blog.holtzweb.com/posts/opnsense-with-haproxy-and-lets-encrypt/#haproxy-inital-configuration
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/audiobookshelf-app#1230