microg/GmsCore · error · RuntimeException
Failed to read license or metadata
Error message
Failed to read license or metadata
What it means
readStringAndClose wraps any IOException thrown while reading up to bytesToRead from the stream into a RuntimeException with this message. Callers are metadata reading (getLicensesFromMetadata) and getLicenseText, so a failure opening or reading third_party_license_metadata or third_party_licenses surfaces here.
Source
Thrown at play-services-oss-licenses/src/main/java/org/microg/gms/oss/licenses/LicenseUtil.java:96
}
} 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;
while (bytesToRead > 0 && (read = is.read(bytes, 0, Math.min(bytes.length, bytesToRead))) != -1) {
bos.write(bytes, 0, read);
bytesToRead -= read;
}
is.close();
} catch (IOException e) {
throw new RuntimeException("Failed to read license or metadata", e);
}
try {
return bos.toString("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Unsupported encoding UTF8. This should always be supported.", e);
}
}
}
View on GitHub (pinned to 157c9d86ac)
Solutions
- Check with LicenseUtil.hasLicenses(context) before reading, and ensure res/raw/third_party_license_metadata and third_party_licenses exist in the app package (not another package/packageId)
- Verify getIdentifier uses the correct package name — reading resources of a different package yields unusable streams
- Catch the RuntimeException with cause IOException and degrade gracefully (show empty license list) or retry after app data repair
- Rebuild/reinstall the app if resources are corrupted
Example fix
// before
String metadata = readStringAndClose(resources.openRawResource(id), Integer.MAX_VALUE);
// after
if (!LicenseUtil.hasLicenses(context)) return Collections.emptyList();
try {
List<License> l = LicenseUtil.getLicensesFromMetadata(context);
} catch (RuntimeException e) {
Log.w("Licenses", "Failed to read license metadata", e);
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!LicenseUtil.hasLicenses(context)) {
return Collections.emptyList(); // skip metadata read entirely
} Try / catch
try {
List<License> licenses = LicenseUtil.getLicensesFromMetadata(context);
} catch (RuntimeException e) {
Log.w("Licenses", "License metadata unreadable", e);
licenses = Collections.emptyList();
} Prevention
- Call hasLicenses(context) first to confirm both raw resources exist and are non-empty
- Ensure the raw resources are in your app's own package so getIdentifier resolves them
- Catch RuntimeException around all LicenseUtil reads and render a graceful empty state
When it happens
Trigger: getLicensesFromMetadata or getLicenseText called when the underlying raw resource cannot be read: Resources.openRawResource returned a stream that fails on read (I/O error), stream already closed, or storage error mid-read.
Common situations: resources.getIdentifier returning an invalid/foreign-package resource so the stream is broken; corrupted resources.arsc; low-level I/O failure on device storage; reading a stream consumed elsewhere.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Could not read from parcel file descriptor
- Resources have not been initialized
- does not contain res/raw/third_party_licenses
- Unsupported encoding UTF8. This should always be supported.
- Failed to create directories: ${parentDir.absolutePath}
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/41369440e7d03403.
Report an issue: GitHub.