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

  1. 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)
  2. Verify getIdentifier uses the correct package name — reading resources of a different package yields unusable streams
  3. Catch the RuntimeException with cause IOException and degrade gracefully (show empty license list) or retry after app data repair
  4. 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

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


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