Tencent/matrix · error · IOException
Can't read mapping file
Error message
Can't read mapping file
What it means
MappingReader.read() parses a ProGuard/R8 mapping.txt file line by line to enable stack-trace retrace. Any IOException encountered while reading the file (including from the wrapped BufferedReader) is caught and rethrown as a new IOException with the message "Can't read mapping file", preserving the original cause. This tells you the mapping file itself could not be read, not that its content was semantically wrong.
Solutions
- Check the underlying cause (err.getCause()) to see whether it is FileNotFoundException, permission denied, or another I/O failure.
- Verify the mapping file path passed to MappingReader exists and is a readable regular file before calling read().
- Ensure the file is not opened twice / not closed by another component before read() runs.
- In CI, confirm the mapping.txt artifact from the ProGuard/R8 task is produced and copied to the expected location.
Example fix
// before
MappingReader reader = new MappingReader(new File(mappingPath));
reader.read(sink);
// after
File f = new File(mappingPath);
if (!f.isFile() || !f.canRead()) {
throw new IllegalStateException("mapping file missing or unreadable: " + mappingPath);
}
try {
new MappingReader(f).read(sink);
} catch (IOException e) {
e.printStackTrace(); // inspect getCause() for the real reason
} Defensive patterns
Strategy: try-catch
Validate before calling
File f = new File(mappingPath);
if (f == null || !f.isFile() || !f.canRead() || f.length() == 0) {
throw new IllegalStateException("mapping file missing/unreadable: " + mappingPath);
} Try / catch
try {
new MappingReader(mappingFile).read(sink);
} catch (IOException e) {
Throwable cause = e.getCause();
if (cause instanceof FileNotFoundException) {
// fix path / regenerate mapping
}
log.warn("retrace skipped: mapping unreadable", e);
} Prevention
- Always verify the mapping file exists and is readable before retrace.
- In CI, fail fast if the ProGuard/R8 mapping artifact is missing after a build.
- Log e.getCause() to distinguish missing file vs permissions vs mid-read I/O errors.
When it happens
Trigger: Calling MappingReader.read() (typically from run()) when the mapping file path does not exist, is unreadable due to permissions, is already closed/corrupt, or the underlying stream hits an I/O error mid-parse (disk error, interrupted stream).
Common situations: Build/CI pipelines that pass a missing or stale mapping.txt path after a clean; retrace tools pointed at a renamed obfuscation output directory; reading the mapping from storage the process lacks permission for; transient disk or file-descriptor issues.
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
- Method is not exists.
- TaskInitException wrapping e.getMessage()…
- ---The Proguard mapping file 'mapping.txt' is not legal!
- ---mapping file <config.getMappingFilePath()> is not legal!
- ---resguard mapping file <config.getResMappingFilePath()>…
AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08).
Data as JSON: /api/errors/0787c183a4162394.
Report an issue: GitHub.
Appendix: source
Thrown at matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/trace/retrace/MappingReader.java:70
while (true) {
String line = reader.readLine();
if (line == null) {
break;
}
line = line.trim();
if (!line.startsWith("#")) {
// a class mapping
if (line.endsWith(SPLIT)) {
className = parseClassMapping(line, mappingProcessor);
} else if (className != null) { // a class member mapping
parseClassMemberMapping(className, line, mappingProcessor);
}
} else {
Log.i(TAG, "comment:# %s", line);
}
}
} catch (IOException err) {
throw new IOException("Can't read mapping file", err);
} finally {
try {
reader.close();
} catch (IOException ex) {
// do nothing
}
}
}
/**
* @param line read content
* @param mappingProcessor
* @return
*/
private String parseClassMapping(String line, MappingProcessor mappingProcessor) {
int leftIndex = line.indexOf(ARROW);
if (leftIndex < 0) {View on GitHub (pinned to 3b8293bd65)