microg/GmsCore · error · RuntimeException

does not contain res/raw/third_party_licenses

Error message

 does not contain res/raw/third_party_licenses

What it means

getLicenseText throws this RuntimeException when the JAR file referenced by the License's path does not contain a JarEntry named "res/raw/third_party_licenses". The library expects license text for non-empty license paths to live inside an APK/JAR at that exact resource path (as produced by the OSS licenses plugin). If the entry is missing, the offset/length stored in the metadata cannot be resolved, so the library aborts.

Source

Thrown at play-services-oss-licenses/src/main/java/org/microg/gms/oss/licenses/LicenseUtil.java:71

    }

    public static String getLicenseText(Context context, License license) {
        if (license.getPath().isEmpty()) {
            Resources resources = context.getApplicationContext().getResources();
            InputStream is = resources.openRawResource(resources.getIdentifier("third_party_licenses", "raw", context.getPackageName()));
            try {
                if (is.skip(license.getOffset()) != license.getOffset()) {
                    throw new RuntimeException("Failed to read license");
                }
            } catch (IOException e) {
                throw new RuntimeException("Failed to read license", e);
            }
            return readStringAndClose(is, license.getLength());
        } else {
            try (JarFile jar = new JarFile(license.getPath())) {
                JarEntry entry = jar.getJarEntry("res/raw/third_party_licenses");
                if (entry == null) {
                    throw new RuntimeException(license.getPath() + " does not contain res/raw/third_party_licenses");
                } else {
                    InputStream is = jar.getInputStream(entry);
                    if (is.skip(license.getOffset()) != license.getOffset()) {
                        throw new RuntimeException("Failed to read license");
                    }
                    return readStringAndClose(is, license.getLength());
                }
            } catch (IOException e) {
                throw new RuntimeException("Failed to read license", e);
            }
        }
    }

    private static String readStringAndClose(InputStream is, int bytesToRead) {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            byte[] bytes = new byte[1024];
            int read;

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Verify the JAR at license.getPath() actually contains res/raw/third_party_licenses (e.g. unzip -l app.apk | grep third_party_licenses) and rebuild it with the OSS licenses plugin if missing
  2. Ensure resource shrinking/minification (e.g. shrinkResources, keep rules) is not stripping res/raw/third_party_licenses from the artifact
  3. Confirm the License instance came from getLicensesFromMetadata of the same app/artifact it is read from; regenerate metadata and licenses together
  4. If licenses live in Android resources rather than a JAR, use a License with an empty path so getLicenseText reads via Resources.openRawResource instead

Example fix

// before
License license = new License(title, offset, length, "/data/app/stripped.apk");
String text = LicenseUtil.getLicenseText(context, license);
// after
// rebuild the artifact with the OSS licenses plugin so res/raw/third_party_licenses exists,
// or load from app resources with an empty path:
License license = new License(title, offset, length, ""); // empty path -> raw resource branch
String text = LicenseUtil.getLicenseText(context, license);
Defensive patterns

Strategy: validation

Validate before calling

static boolean jarHasLicenses(String path) {
    try (JarFile jar = new JarFile(path)) {
        return jar.getJarEntry("res/raw/third_party_licenses") != null;
    } catch (IOException e) { return false; }
}
// call jarHasLicenses(license.getPath()) before getLicenseText when path is non-empty

Try / catch

try {
    text = LicenseUtil.getLicenseText(context, license);
} catch (RuntimeException e) {
    Log.w("Licenses", "Missing res/raw/third_party_licenses in " + license.getPath(), e);
    text = null; // fallback path
}

Prevention

When it happens

Trigger: Calling LicenseUtil.getLicenseText(context, license) where license.getPath() is non-empty (a JAR/APK path) but the JAR was built without the third_party_licenses raw resource, was repackaged/stripped by a build step, or the path points to a different artifact than the one the metadata was generated against.

Common situations: ProGuard/resource shrinkers or custom packaging removing res/raw entries; using a License object deserialized from another app version whose JAR layout differs; pointing at a debug or stub artifact that lacks the licenses resource; manually constructing License with an arbitrary file path.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06). Data as JSON: /api/errors/506e21626ae856d8. Report an issue: GitHub.