apache/maven · error · XmlWriterException
Unable to write toolchains: {}
Error message
Unable to write toolchains: {} What it means
Thrown by ToolchainsXmlFactory.write (DefaultToolchainsXmlFactory) when serializing a PersistedToolchains model to XML fails. The method wraps every exception raised by the StAX writer while writing to the supplied Writer/OutputStream, and appends the underlying cause's message to 'Unable to write toolchains: '. Typical root causes are I/O failures (read-only or missing output path, closed stream, disk full) or a model containing values the toolchains writer cannot serialize.
Source
Thrown at impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultToolchainsXmlFactory.java:102
}
try {
MavenToolchainsStaxWriter xmlWriter = new MavenToolchainsStaxWriter();
xmlWriter.setAddLocationInformation(false);
Function<Object, String> formatter = request.getInputLocationFormatter();
if (formatter != null) {
xmlWriter.setAddLocationInformation(true);
Function<InputLocation, String> adapter = formatter::apply;
xmlWriter.setStringFormatter(adapter);
}
if (writer != null) {
xmlWriter.write(writer, content);
} else {
xmlWriter.write(outputStream, content);
}
} catch (Exception e) {
throw new XmlWriterException("Unable to write toolchains: " + getMessage(e), getLocation(e), e);
}
}
}
View on GitHub (pinned to e4093d4e12)
Solutions
- Read the appended cause message and inspect XmlWriterException.getCause() to distinguish IOException (output target problem) from a model/serialization problem
- Verify the output file is writable and the stream/writer is still open before calling write
- Round-trip the model: read toolchains with the same factory, modify the result, and write it back instead of constructing PersistedToolchains by hand
- Ensure every Toolchain entry has a non-null type and a non-null parameters map before writing
Example fix
// before: hand-built model, closed stream
PersistedToolchains tc = new PersistedToolchains();
tc.addToolchain(new Toolchain(null, null)); // null type
factory.write(XmlWriterRequest.builder().content(tc).outputStream(closedOut).build());
// after: round-trip a valid model to a writable target
PersistedToolchains tc = factory.read(XmlReaderRequest.builder().path(toolchainsPath).build());
tc.getToolchains().get(0).getParameters().put("jdk", "17");
try (OutputStream out = Files.newOutputStream(toolchainsPath)) {
factory.write(XmlWriterRequest.builder().content(tc).outputStream(out).build());
} Defensive patterns
Strategy: try-catch
Validate before calling
// before writing toolchains
Path out = toolchainsPath;
if (!Files.isWritable(out.getParent() == null ? Path.of(".") : out.getParent())) {
throw new IllegalStateException("toolchains output directory not writable: " + out);
}
for (Toolchain tc : content.getToolchains()) {
Objects.requireNonNull(tc.getType(), "toolchain type");
Objects.requireNonNull(tc.getParameters(), "toolchain parameters");
} Try / catch
try {
toolchainsXmlFactory.write(request);
} catch (XmlWriterException e) {
Throwable cause = e.getCause();
if (cause instanceof IOException io) {
// output target problem: permissions, closed stream, disk full
throw new IllegalStateException("Cannot write toolchains to target: " + io.getMessage(), e);
}
throw e; // model/serialization problem: fix the content
} Prevention
- Round-trip toolchains.xml with the same factory (read, modify, write) instead of hand-building PersistedToolchains
- Keep the output stream open and owned by the write call; do not reuse streams from prior operations
- Validate that every Toolchain has a non-null type and parameters map before writing
When it happens
Trigger: Calling ToolchainsXmlFactory.write(XmlWriterRequest) with an OutputStream/Writer that is closed or targets a read-only file; passing a hand-built PersistedToolchains whose toolchain entries contain null type or null parameters; disk exhaustion during the write.
Common situations: Programmatic editing of ~/.m2/toolchains.xml through the Maven API where the model was assembled manually instead of round-tripped; CI agents with full disks; writing to a directory the process does not own; a partially-populated model after a failed read-modify-write cycle.
Related errors
- Unable to write model:
- Unable to write plugin:
- Unable to write settings: {}
- Cannot read toolchains file at " + userToolchainsFile.getAbs
- Problem during inlining POM
AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21).
Data as JSON: /api/errors/de556dbf9b97380f.
Report an issue: GitHub.