shwenzhang/AndResGuard · error · RuntimeException

Failed to read resource

Error message

Failed to read <page> resource

What it means

printUsage reads a usage/help page from the classpath via getResourceAsStream and prints it. When reading the stream throws an IOException, it is rethrown as a RuntimeException "Failed to read <page> resource". This means the tool could not read its own bundled help text, typically because the resource is missing from the packaged jar or the stream failed mid-read.

Solutions

  1. Use the intact AndResGuard/apksigner build artifact so the usage text resources (e.g. /apksigner/help/*.txt) are on the classpath.
  2. If running from an IDE or fat jar, add a resources-inclusion rule (keep the help resource files) to the build config.
  3. Report/patch printUsage to handle a null stream explicitly instead of relying on IOException.
  4. As a workaround, consult apksigner usage documentation offline instead of triggering the help page.

Example fix

// before
} catch (IOException e) {
  throw new RuntimeException("Failed to read " + page + " resource");
}
// after
} catch (IOException | NullPointerException e) {
  throw new RuntimeException("Failed to read " + page + " resource - resource missing on classpath", e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

java
URL url = ApkSignerTool.class.getResource(page);
if (url == null) {
    throw new IllegalStateException("Usage page resource missing from classpath: " + page);
}

Try / catch

java
try {
    printUsage(page);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Failed to read")) {
        System.err.println("Help resources missing; see online docs instead.");
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Running main/sign/verify which calls printUsage("/apksigner/help/...") when usage output is required, and the classpath resource referenced by `page` is absent (getResourceAsStream returns null, causing NPE/IOException on read) or the underlying stream throws IOException while reading.

Common situations: Running a repackaged/proguarded jar where the help text resources were stripped; invoking apksigner classes from a classpath that excludes the resource directory; corrupted or partially extracted build artifact.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of shwenzhang/AndResGuard@e4df245d82 (2026-09-12). Data as JSON: /api/errors/09f013d4e18ce908. Report an issue: GitHub.

Appendix: source

Thrown at AndResGuard-core/src/main/java/apksigner/ApkSignerTool.java:495

      return;
    }
    if ((warningsTreatedAsErrors) && (warningsEncountered)) {
      System.exit(1);
      return;
    }
  }

  private static void printUsage(String page) {
    try (BufferedReader in = new BufferedReader(new InputStreamReader(
        ApkSignerTool.class.getResourceAsStream(page),
        StandardCharsets.UTF_8
    ))) {
      String line;
      while ((line = in.readLine()) != null) {
        System.out.println(line);
      }
    } catch (IOException e) {
      throw new RuntimeException("Failed to read " + page + " resource");
    }
  }

  private static byte[] readFully(File file) throws IOException {
    ByteArrayOutputStream result = new ByteArrayOutputStream();
    try (FileInputStream in = new FileInputStream(file)) {
      drain(in, result);
    }
    return result.toByteArray();
  }

  private static void drain(InputStream in, OutputStream out) throws IOException {
    byte[] buf = new byte[65536];
    int chunkSize;
    while ((chunkSize = in.read(buf)) != -1) {
      out.write(buf, 0, chunkSize);
    }
  }

View on GitHub (pinned to e4df245d82)