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

  1. Create a new TemplateFile instance (via fromResources or a fresh InputStream) for each render call.
  2. If you need the output multiple times, call build() once and reuse the resulting String.
  3. 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

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


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