{"record":{"id":"5e5b645452f0c239","repo":"microg/GmsCore","slug":"failed-to-read-license","errorCode":null,"errorMessage":"Failed to read license","messagePattern":"Failed to read license","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"play-services-oss-licenses/src/main/java/org/microg/gms/oss/licenses/LicenseUtil.java","lineNumber":61,"sourceCode":"        List<License> licenses = new ArrayList<>(lines.length);\n        for (String line : lines) {\n            int spaceIndex = line.indexOf(' ');\n            String[] position = line.substring(0, spaceIndex).split(\":\");\n            if (spaceIndex <= 0 || position.length != 2) {\n                throw new IllegalStateException(\"Invalid license meta-data line:\\n\" + line);\n            }\n            licenses.add(new License(line.substring(spaceIndex + 1), Long.parseLong(position[0]), Integer.parseInt(position[1]), \"\"));\n        }\n        return licenses;\n    }\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) {","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-oss-licenses/src/main/java/org/microg/gms/oss/licenses/LicenseUtil.java#L43-L79","documentation":"getLicenseText skips license.getOffset() bytes into the packaged third_party_licenses raw resource; if InputStream.skip() returns fewer bytes than requested, the offset is unreachable (file shorter or truncated) and a RuntimeException 'Failed to read license' is thrown. IOException during skip is wrapped in the same error.","triggerScenarios":"Calling getLicenseText for a License whose offset exceeds the size of the res/raw/third_party_licenses resource, or when openRawResource/getIdentifier returned a mismatched resource; also any IOException raised while skipping.","commonSituations":"The licenses index/metadata was regenerated but the raw resource file is stale (offsets point past the end); resource name 'third_party_licenses' overridden or missing in the app's package; a shrinker stripped or altered the raw resource.","solutions":["Regenerate the third_party_licenses raw resource and its metadata together so offsets match","Verify res/raw/third_party_licenses exists and contains the license text at the given offset","Check that resource shrinking/minification is not removing or renaming the raw resource"],"exampleFix":"// no code fix at call site; regenerate resources so offsets align\n// before: metadata offset 9000 but third_party_licenses file is only 5000 bytes\n// after: rebuild license bundle so offsets are within file size","handlingStrategy":"try-catch","validationCode":"// Check the raw resource is at least offset+length bytes before reading\nResources res = context.getResources();\nint id = res.getIdentifier(\"third_party_licenses\", \"raw\", context.getPackageName());\nif (id == 0) throw new IllegalStateException(\"third_party_licenses raw resource missing\");\ntry (InputStream is = res.openRawResource(id)) {\n    if (is.skip(license.getOffset()) != license.getOffset()) {\n        throw new IllegalStateException(\"Offset \" + license.getOffset() + \" beyond resource\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    String text = LicenseUtil.getLicenseText(context, license);\n} catch (RuntimeException e) {\n    Log.e(TAG, \"Could not read license \" + license.getTitle() + \": \" + e.getMessage());\n    text = \"\";\n}","preventionTips":["Regenerate metadata and raw license text in the same build so offsets stay in sync","Verify resource shrinking does not strip res/raw/third_party_licenses","Check that getIdentifier resolves the resource in the app (not library) package"],"tags":["java","io","oss-licenses","android-resources"],"backgroundTag":"file-read-failed","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}