skylot/jadx · error · IOException
Template already processed
Error message
Template already processed
What it means
Thrown as IOException by TemplateFile.process() when template.available() == 0, indicating the underlying InputStream has already been fully consumed. TemplateFile wraps a single InputStream and is designed for single-use: calling build() or save() consumes the stream. A second call finds no bytes available and throws.
Source
Thrown at jadx-core/src/main/java/jadx/core/export/TemplateFile.java:79
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
process(out);
return out.toString();
}
}
public void save(File outFile) throws IOException {
try (OutputStream out = new FileOutputStream(outFile)) {
process(out);
}
}
public void setValueSanitizer(@Nullable Function<String, String> valueSanitizer) {
this.valueSanitizer = valueSanitizer;
}
private void process(OutputStream out) throws IOException {
if (template.available() == 0) {
throw new IOException("Template already processed");
}
try (InputStream in = new BufferedInputStream(template)) {
ParserState state = new ParserState();
while (true) {
int ch = in.read();
if (ch == -1) {
break;
}
String str = process(state, (char) ch);
if (str != null) {
out.write(str.getBytes());
} else if (!state.skip) {
out.write(ch);
}
}
}
}
View on GitHub (pinned to e738a26571)
Solutions
- Create a new TemplateFile instance (via fromResources or a fresh InputStream) for each render call.
- If you need the output multiple times, call build() once and reuse the resulting String.
- If developing jadx export code, load the template fresh for each file write.
Example fix
// before — reusing a single TemplateFile
TemplateFile tmpl = TemplateFile.fromResources("/export/x.tmpl");
tmpl.add("name", value);
tmpl.save(file1);
tmpl.save(file2); // IOException: already processed
// after — create fresh instances
TemplateFile tmpl1 = TemplateFile.fromResources("/export/x.tmpl");
tmpl1.add("name", value);
tmpl1.save(file1);
TemplateFile tmpl2 = TemplateFile.fromResources("/export/x.tmpl");
tmpl2.add("name", value);
tmpl2.save(file2); Defensive patterns
Strategy: validation
Validate before calling
// TemplateFile is single-use; create a fresh instance for each render
// Do NOT reuse the same TemplateFile instance
TemplateFile tmpl1 = TemplateFile.fromResources(path);
tmpl1.add("key", value);
String result = tmpl1.build(); // consumes the stream
// For a second render, create a new instance
TemplateFile tmpl2 = TemplateFile.fromResources(path);
tmpl2.add("key", value);
tmpl2.save(outputFile); Try / catch
try {
tmpl.save(outFile);
} catch (IOException e) {
if (e.getMessage().contains("already processed")) {
// Recreate the template and retry
tmpl = TemplateFile.fromResources(originalPath);
tmpl.add("key", value);
tmpl.save(outFile);
} else {
throw e;
}
} Prevention
- Never call build() or save() twice on the same TemplateFile instance.
- If you need output in memory and on disk, call build() once and write the String to disk separately.
- Create a fresh TemplateFile for each file write in export code.
When it happens
Trigger: TemplateFile.build() or TemplateFile.save() is called more than once on the same TemplateFile instance. The first call drains the InputStream; the second call sees available() == 0 and throws.
Common situations: Internal jadx code that caches a TemplateFile and attempts to render it twice (e.g. once for preview, once for save). Custom code reusing a TemplateFile instance. Not user-facing in normal decompilation — typically a programming error in export or template-consuming code.
Related errors
- Failed to generate gradle files
- Failed to save JSON file: {}
- Failed to save JSON file: {}
- Failed to init common directories
- Failed to create temp root directory
AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14).
Data as JSON: /api/errors/67b4bdd7d9d1869c.
Report an issue: GitHub.