google/ExoPlayer · error · MediaDrmCallbackException

No license URL

Error message

No license URL

What it means

HttpMediaDrmCallback.executeKeyRequest() must resolve a license server URL for every key/license request. It first uses the URL embedded in the KeyRequest (which comes from the DRM init data / MediaDrm), and if forceDefaultLicenseUrl is set or that URL is empty it falls back to defaultLicenseUrl (the constructor argument). If both are empty it throws MediaDrmCallbackException wrapping IllegalStateException("No license URL"), aborting key acquisition.

Source

Thrown at library/core/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java:145

  public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request)
      throws MediaDrmCallbackException {
    String url =
        request.getDefaultUrl() + "&signedRequest=" + Util.fromUtf8Bytes(request.getData());
    return executePost(
        dataSourceFactory,
        url,
        /* httpBody= */ null,
        /* requestProperties= */ Collections.emptyMap());
  }

  @Override
  public byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws MediaDrmCallbackException {
    String url = request.getLicenseServerUrl();
    if (forceDefaultLicenseUrl || TextUtils.isEmpty(url)) {
      url = defaultLicenseUrl;
    }
    if (TextUtils.isEmpty(url)) {
      throw new MediaDrmCallbackException(
          new DataSpec.Builder().setUri(Uri.EMPTY).build(),
          Uri.EMPTY,
          /* responseHeaders= */ ImmutableMap.of(),
          /* bytesLoaded= */ 0,
          /* cause= */ new IllegalStateException("No license URL"));
    }
    Map<String, String> requestProperties = new HashMap<>();
    // Add standard request properties for supported schemes.
    String contentType =
        C.PLAYREADY_UUID.equals(uuid)
            ? "text/xml"
            : (C.CLEARKEY_UUID.equals(uuid) ? "application/json" : "application/octet-stream");
    requestProperties.put("Content-Type", contentType);
    if (C.PLAYREADY_UUID.equals(uuid)) {
      requestProperties.put(
          "SOAPAction", "http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense");
    }
    // Add additional request properties.

View on GitHub (pinned to dd430f7053)

Solutions

  1. Pass an explicit default license URL when constructing the callback: new HttpMediaDrmCallback("https://license.example.com/path", dataSourceFactory) — this covers content lacking an embedded URL.
  2. If URLs are embedded per-stream, keep them but do NOT set forceDefaultLicenseUrl(true) with an empty default; either supply both or rely on the embedded URL.
  3. Fix the packaging side: include the license URL in the manifest (DASH ContentProtection LaURL / PlayReady PRO) or in the ClearKey JSON so request.getLicenseServerUrl() is non-empty.
  4. Log which path produced the empty URL (embedded vs default) to confirm whether content or app config is at fault.

Example fix

// before
DrmSessionManager drm = new DefaultDrmSessionManager.Builder()
    .setUuidAndExoMediaDrmProvider(C.WIDEVINE_UUID, FrameworkMediaDrm.DEFAULT_PROVIDER)
    .build(new HttpMediaDrmCallback("", httpDataSourceFactory)); // empty default

// after
DrmSessionManager drm = new DefaultDrmSessionManager.Builder()
    .setUuidAndExoMediaDrmProvider(C.WIDEVINE_UUID, FrameworkMediaDrm.DEFAULT_PROVIDER)
    .build(new HttpMediaDrmCallback("https://license.example.com/widevine", httpDataSourceFactory));
Defensive patterns

Strategy: validation

Validate before calling

String licenseUrl = "https://license.example.com/widevine"; // app config
HttpMediaDrmCallback callback = new HttpMediaDrmCallback(licenseUrl, httpDataSourceFactory);
// Guard: never construct with an empty/blank default when init data may lack a URL
if (licenseUrl == null || licenseUrl.trim().isEmpty()) {
  throw new IllegalStateException("HttpMediaDrmCallback requires a license URL for this content");
}

Try / catch

@Override
public void onPlayerError(PlaybackException error) {
  if (error.getCause() instanceof DrmSessionException
      && error.getCause().getCause() instanceof MediaDrmCallbackException) {
    MediaDrmCallbackException drmEx = (MediaDrmCallbackException) error.getCause().getCause();
    if (drmEx.getCause() instanceof IllegalStateException
        && "No license URL".equals(drmEx.getCause().getMessage())) {
      // surface 'DRM not configured' UI instead of a generic playback failure
    }
  }
}

Prevention

When it happens

Trigger: Calling new HttpMediaDrmCallback(null /* or "" */, dataSourceFactory) and playing content whose DRM init data carries no license URL (e.g. DASH ContentProtection without LaURL, raw PSSH boxes without a URL); setting forceDefaultLicenseUrl=true while defaultLicenseUrl is empty; ClearKey where the JSON/media path omitted the license server; PlayReady where LaURL was stripped from the manifest.

Common situations: License server passed only in the manifest on some streams but not others; test streams with bare PSSH init data; typos like passing a placeholder empty string; migrating from LocalMediaDrmCallback to HttpMediaDrmCallback and forgetting the URL argument; CDN/manifest re-packagers that drop LaURL from ContentProtection elements.

Related errors


AI-assisted analysis of google/ExoPlayer@dd430f7053 (2026-08-14). Data as JSON: /api/errors/f8a9f200de5d4be4. Report an issue: GitHub.