{"record":{"id":"506e21626ae856d8","repo":"microg/GmsCore","slug":"does-not-contain-res-raw-third-party-licenses","errorCode":null,"errorMessage":" does not contain res/raw/third_party_licenses","messagePattern":" does not contain res/raw/third_party_licenses","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"play-services-oss-licenses/src/main/java/org/microg/gms/oss/licenses/LicenseUtil.java","lineNumber":71,"sourceCode":"    }\n\n    public static String getLicenseText(Context context, License license) {\n        if (license.getPath().isEmpty()) {\n            Resources resources = context.getApplicationContext().getResources();\n            InputStream is = resources.openRawResource(resources.getIdentifier(\"third_party_licenses\", \"raw\", context.getPackageName()));\n            try {\n                if (is.skip(license.getOffset()) != license.getOffset()) {\n                    throw new RuntimeException(\"Failed to read license\");\n                }\n            } catch (IOException e) {\n                throw new RuntimeException(\"Failed to read license\", e);\n            }\n            return readStringAndClose(is, license.getLength());\n        } else {\n            try (JarFile jar = new JarFile(license.getPath())) {\n                JarEntry entry = jar.getJarEntry(\"res/raw/third_party_licenses\");\n                if (entry == null) {\n                    throw new RuntimeException(license.getPath() + \" does not contain res/raw/third_party_licenses\");\n                } else {\n                    InputStream is = jar.getInputStream(entry);\n                    if (is.skip(license.getOffset()) != license.getOffset()) {\n                        throw new RuntimeException(\"Failed to read license\");\n                    }\n                    return readStringAndClose(is, license.getLength());\n                }\n            } catch (IOException e) {\n                throw new RuntimeException(\"Failed to read license\", e);\n            }\n        }\n    }\n\n    private static String readStringAndClose(InputStream is, int bytesToRead) {\n        ByteArrayOutputStream bos = new ByteArrayOutputStream();\n        try {\n            byte[] bytes = new byte[1024];\n            int read;","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-oss-licenses/src/main/java/org/microg/gms/oss/licenses/LicenseUtil.java#L53-L89","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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","Ensure resource shrinking/minification (e.g. shrinkResources, keep rules) is not stripping res/raw/third_party_licenses from the artifact","Confirm the License instance came from getLicensesFromMetadata of the same app/artifact it is read from; regenerate metadata and licenses together","If licenses live in Android resources rather than a JAR, use a License with an empty path so getLicenseText reads via Resources.openRawResource instead"],"exampleFix":"// before\nLicense license = new License(title, offset, length, \"/data/app/stripped.apk\");\nString text = LicenseUtil.getLicenseText(context, license);\n// after\n// rebuild the artifact with the OSS licenses plugin so res/raw/third_party_licenses exists,\n// or load from app resources with an empty path:\nLicense license = new License(title, offset, length, \"\"); // empty path -> raw resource branch\nString text = LicenseUtil.getLicenseText(context, license);","handlingStrategy":"validation","validationCode":"static boolean jarHasLicenses(String path) {\n    try (JarFile jar = new JarFile(path)) {\n        return jar.getJarEntry(\"res/raw/third_party_licenses\") != null;\n    } catch (IOException e) { return false; }\n}\n// call jarHasLicenses(license.getPath()) before getLicenseText when path is non-empty","typeGuard":null,"tryCatchPattern":"try {\n    text = LicenseUtil.getLicenseText(context, license);\n} catch (RuntimeException e) {\n    Log.w(\"Licenses\", \"Missing res/raw/third_party_licenses in \" + license.getPath(), e);\n    text = null; // fallback path\n}","preventionTips":["Keep the OSS licenses Gradle plugin enabled so res/raw/third_party_licenses is always packaged","Check resource shrinker output (apk analyzer) after release builds to confirm the raw resource survives","Only pass License objects produced by getLicensesFromMetadata of the same artifact"],"tags":["android","jar","licensing","resource-not-found"],"backgroundTag":"resource-not-found","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}