{"record":{"id":"01e196cb2f91e285","repo":"google/ExoPlayer","slug":"playback-stuck-buffering-and-not-loading","errorCode":null,"errorMessage":"Playback stuck buffering and not loading","messagePattern":"Playback stuck buffering and not loading","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java","lineNumber":1128,"sourceCode":"      if (!playbackInfo.isLoading\n          && playbackInfo.totalBufferedDurationUs < PLAYBACK_BUFFER_EMPTY_THRESHOLD_US\n          && isLoadingPossible()) {\n        // The renderers are not ready, there is more media available to load, and the LoadControl\n        // is refusing to load it (indicated by !playbackInfo.isLoading). This could be because the\n        // renderers are still transitioning to their ready states, but it could also indicate a\n        // stuck playback. The playbackInfo.totalBufferedDurationUs check further isolates the\n        // cause to a lack of media for the renderers to consume, to avoid classifying playbacks as\n        // stuck when they're waiting for other reasons (in particular, loading DRM keys).\n        playbackMaybeStuck = true;\n      }\n    }\n\n    if (!playbackMaybeStuck) {\n      playbackMaybeBecameStuckAtMs = C.TIME_UNSET;\n    } else if (playbackMaybeBecameStuckAtMs == C.TIME_UNSET) {\n      playbackMaybeBecameStuckAtMs = clock.elapsedRealtime();\n    } else if (clock.elapsedRealtime() - playbackMaybeBecameStuckAtMs >= PLAYBACK_STUCK_AFTER_MS) {\n      throw new IllegalStateException(\"Playback stuck buffering and not loading\");\n    }\n\n    boolean isPlaying = shouldPlayWhenReady() && playbackInfo.playbackState == Player.STATE_READY;\n    boolean sleepingForOffload = offloadSchedulingEnabled && requestForRendererSleep && isPlaying;\n    if (playbackInfo.sleepingForOffload != sleepingForOffload) {\n      playbackInfo = playbackInfo.copyWithSleepingForOffload(sleepingForOffload);\n    }\n    requestForRendererSleep = false; // A sleep request is only valid for the current doSomeWork.\n\n    if (sleepingForOffload || playbackInfo.playbackState == Player.STATE_ENDED) {\n      // No need to schedule next work.\n    } else if (isPlaying || playbackInfo.playbackState == Player.STATE_BUFFERING) {\n      // We are actively playing or waiting for data to be ready. Schedule next work quickly.\n      scheduleNextWork(operationStartTimeMs, ACTIVE_INTERVAL_MS);\n    } else if (playbackInfo.playbackState == Player.STATE_READY && enabledRendererCount != 0) {\n      // We are ready, but not playing. Schedule next work less often to handle non-urgent updates.\n      scheduleNextWork(operationStartTimeMs, IDLE_INTERVAL_MS);\n    }","sourceCodeStart":1110,"sourceCodeEnd":1146,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java#L1110-L1146","documentation":"ExoPlayerImplInternal's periodic doSomeWork pass monitors the internal playback thread. If playback is in STATE_BUFFERING, renderers cannot make progress, nothing new is being loaded (totalBufferedDurationUs not advancing), and this persists continuously for PLAYBACK_STUCK_AFTER_MS, the internal thread concludes the pipeline is deadlocked and throws an IllegalStateException('Playback stuck buffering and not loading'). The DRM-key-wait case and normal rebuffer are explicitly excluded, so this fires only when neither network loading nor rendering is making any progress.","triggerScenarios":"A renderer or loadable wedges: e.g. a custom DataSource blocking forever on a socket without timeout, a MediaCodec that never returns from dequeueOutputBuffer, a progressive source whose loader thread hangs, or a metered connection where the server stalls mid-stream while the buffer drains to empty.","commonSituations":"Custom DataSource implementations doing blocking I/O without timeouts; HTTP servers that accept the connection but never send bytes; bugs in experimental renderers; device codec drivers locking up. Note this is an internal watchdog crash — it indicates an infrastructure/media bug, not an app-level API misuse.","solutions":["Capture the full stack trace and the player's Loader/codec threads to find which component is blocked.","Set explicit connect/read timeouts on your HttpDataSource (setConnectTimeoutMs/setReadTimeoutMs) so stalls surface as IOExceptions and trigger ExoPlayer's retry logic instead of a hang.","Audit custom DataSource or Renderer implementations for unbounded blocking calls; make them interruptible.","Reproduce with the same media on another device/network to rule out a pathological server or codec; if it is device-specific, report with the stack trace to the ExoPlayer/AndroidX Media issue tracker."],"exampleFix":"// before — no timeouts, a stalled server wedges the loader thread\nnew DefaultHttpDataSource.Factory()\n    .setUserAgent(\"my-app\")\n\n// after\nnew DefaultHttpDataSource.Factory()\n    .setUserAgent(\"my-app\")\n    .setConnectTimeoutMs(8_000)\n    .setReadTimeoutMs(8_000)\n    .setAllowCrossProtocolRedirects(true)","handlingStrategy":"retry","validationCode":"// give every HTTP data source hard deadlines so stalls become retries\nDataSource.Factory http = new DefaultHttpDataSource.Factory()\n    .setConnectTimeoutMs(8_000)\n    .setReadTimeoutMs(8_000);","typeGuard":null,"tryCatchPattern":"player.addListener(new Player.Listener() {\n  @Override public void onPlayerError(PlaybackException error) {\n    if (error.getErrorCode()\n        == PlaybackException.ERROR_CODE_PLAYBACK_STUCK) { // internal watchdog fired\n      logDiagnostics(error);          // full stack + player state\n      scheduleRecover();              // rebuild player and retry current item once\n    }\n  }\n});","preventionTips":["Set connect/read timeouts on all network DataSources","Make custom DataSources interruptible; never block the loader thread indefinitely","Keep a LoadErrorHandlingPolicy configured with sane retry windows","Collect the stuck stack trace per device model and report codec/HAL-specific repros upstream"],"tags":["exoplayer","buffering","watchdog","deadlock","network","codec"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}