skylot/jadx · error · JadxRuntimeException

Failed to read res-map file

Error message

Failed to read res-map file

What it means

Thrown when TextResMapFile.read(InputStream) fails to parse a text res-map file. The read loop delegates each line to parseLine, which expects exactly 8 hex characters at offset 0 (SPLIT_POS=8), followed by '=' and the resource name. Any malformed line (shorter than 8 chars, non-hex ID, missing '=') causes NumberFormatException or StringIndexOutOfBoundsException, which is caught and rewrapped as JadxRuntimeException. I/O failures during readLine() are also wrapped here.

Source

Thrown at jadx-core/src/main/java/jadx/core/utils/android/TextResMapFile.java:32

import jadx.core.utils.exceptions.JadxRuntimeException;

public class TextResMapFile {
	private static final int SPLIT_POS = 8;

	public static Map<Integer, String> read(InputStream is) {
		try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
			Map<Integer, String> resMap = new HashMap<>();
			while (true) {
				String line = br.readLine();
				if (line == null) {
					break;
				}
				parseLine(resMap, line);
			}
			return resMap;
		} catch (Exception e) {
			throw new JadxRuntimeException("Failed to read res-map file", e);
		}
	}

	private static void parseLine(Map<Integer, String> resMap, String line) {
		int id = Integer.parseInt(line.substring(0, SPLIT_POS), 16);
		String name = line.substring(SPLIT_POS + 1);
		resMap.put(id, name);
	}

	public static Map<Integer, String> read(Path resMapFile) {
		try (InputStream in = Files.newInputStream(resMapFile)) {
			return read(in);
		} catch (Exception e) {
			throw new JadxRuntimeException("Failed to read res-map file", e);
		}
	}

	public static void write(Path resMapFile, Map<Integer, String> inputResMap) {

View on GitHub (pinned to e738a26571)

Solutions

  1. Validate the res-map file format before passing it: every non-empty line must match the regex '^[0-9a-fA-F]{8}=..*$'.
  2. If the file was hand-edited, re-export it via TextResMapFile.write so it uses the exact '%08x=%s' format.
  3. Check the wrapped cause in the JadxRuntimeException (getCause()) to distinguish parse errors (NumberFormatException/StringIndexOutOfBoundsException) from I/O errors (IOException).
  4. If reading from a stream, ensure the stream is open and not already consumed before calling read().

Example fix

// before
Map<Integer,String> map = TextResMapFile.read(Files.newInputStream(path));

// after — guard against malformed lines by pre-validating
try (BufferedReader br = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
    String line;
    while ((line = br.readLine()) != null) {
        if (!line.matches("^[0-9a-fA-F]{8}=.*$")) continue; // skip malformed
    }
}
Map<Integer,String> map = TextResMapFile.read(Files.newInputStream(path));
Defensive patterns

Strategy: validation

Validate before calling

// Validate each line matches the '080028f0=name' format before calling read()
public static boolean isValidResMapFormat(Path path) throws IOException {
    try (BufferedReader br = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
        String line;
        while ((line = br.readLine()) != null) {
            if (line.isEmpty()) continue;
            if (line.length() < 9 || line.charAt(8) != '=') return false;
            String hexPart = line.substring(0, 8);
            for (char c : hexPart.toCharArray()) {
                if (Character.digit(c, 16) == -1) return false;
            }
        }
    }
    return true;
}

Try / catch

try {
    Map<Integer, String> map = TextResMapFile.read(inputStream);
} catch (JadxRuntimeException e) {
    Throwable cause = e.getCause();
    if (cause instanceof NumberFormatException || cause instanceof StringIndexOutOfBoundsException) {
        LOG.error("Malformed res-map line: {}", cause.getMessage());
    } else if (cause instanceof IOException) {
        LOG.error("I/O error reading res-map: {}", cause.getMessage());
    }
}

Prevention

When it happens

Trigger: Calling TextResMapFile.read(InputStream) with a stream whose content does not conform to the '080028f0=resource_name' line format. Specifically: a line shorter than 8 characters (substring(0, SPLIT_POS) throws StringIndexOutOfBoundsException), a line whose first 8 chars are not valid hex (Integer.parseInt(..., 16) throws NumberFormatException), a line shorter than 9 chars (substring(SPLIT_POS + 1) throws), or a closed/null underlying stream (IOException from readLine).

Common situations: A user-edited or externally generated res-map file that uses a different delimiter (space, tab, colon) instead of '='. A file saved with CRLF where a stray '\r' ends up in the hex portion. A truncated or corrupted res-map file from a failed extraction. A pipe/stream that was already closed before being passed in.

Related errors


AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14). Data as JSON: /api/errors/c894451049af6699. Report an issue: GitHub.