apolloconfig/apollo · error · ServiceException
Write app error. {}
Error message
Write app error. {} What it means
Thrown by ConfigsExportService when serializing an App entity to JSON and writing it as a ZipEntry into the export ZipOutputStream fails with an IOException. The error wraps the underlying I/O failure (closed stream, disk full, broken pipe) and aborts the entire export operation. The '{}' placeholder is meant to receive the cause but is actually passed the exception object, not the app, due to argument ordering.
Source
Thrown at apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ConfigsExportService.java:203
// app admin permission filter
return apps.stream().filter(isAppAdmin).collect(Collectors.toList());
}
private void writeAppInfoToZip(List<App> apps, ZipOutputStream zipOutputStream) {
logger.info("to import app size = {}", apps.size());
final Consumer<App> appConsumer = app -> {
try {
synchronized (zipOutputStream) {
String fileName = ConfigFileUtils.genAppInfoPath(app);
String content = gson.toJson(app);
writeToZip(fileName, content, zipOutputStream);
}
} catch (IOException e) {
logger.error("Write error. {}", app);
throw new ServiceException("Write app error. {}", e);
}
};
apps.forEach(appConsumer);
}
private void exportAppNamespaces(ZipOutputStream zipOutputStream) {
List<AppNamespace> appNamespaces = appNamespaceService.findAll();
logger.info("to import appnamespace size = {}", appNamespaces.size());
Consumer<AppNamespace> appNamespaceConsumer = appNamespace -> {
try {
synchronized (zipOutputStream) {
String fileName = ConfigFileUtils.genAppNamespaceInfoPath(appNamespace);
String content = gson.toJson(appNamespace);
writeToZip(fileName, content, zipOutputStream);View on GitHub (pinned to d95fc18d11)
Solutions
- Check portal server disk space and ensure the temp/working directory for zip assembly has adequate free space.
- Verify the HTTP client is not timing out or disconnecting before the export completes; increase client read timeout for large app counts.
- Inspect the portal logs for the preceding 'Write error. {app}' line which logs the specific App and the underlying IOException cause.
- Ensure no code path calls zipOutputStream.close() or finish() before all forEach consumers complete.
Example fix
// before
} catch (IOException e) {
logger.error("Write error. {}", app);
throw new ServiceException("Write app error. {}", e);
}
// after - log app AND cause, pass both args
} catch (IOException e) {
logger.error("Write error. app={}, cause={}", app, e.getMessage());
throw new ServiceException("Write app error. app={}, cause={}", e, app, e.getMessage());
} Defensive patterns
Strategy: try-catch
Validate before calling
// Before export, verify the output stream is writable and disk has space
File tempDir = new File(System.getProperty("java.io.tmpdir"));
long freeSpace = tempDir.getUsableSpace();
if (freeSpace < MIN_EXPORT_DISK_BYTES) {
throw new IllegalStateException("Insufficient disk space for export: " + freeSpace);
} Try / catch
try {
configsExportService.exportData(apps, envs, outputStream);
} catch (ServiceException e) {
if (e.getMessage().contains("Write app error")) {
log.error("Export failed during app write, likely I/O or disk issue", e);
// notify user, retry with smaller scope
}
throw e;
} Prevention
- Monitor portal disk space and set alerts for low free space.
- Configure HTTP client timeouts to be longer than the worst-case export duration.
- Avoid concurrent exports that share the same OutputStream or temp directory.
When it happens
Trigger: Calling the config-export API endpoint that drives writeAppInfoToZip() while the ZipOutputStream is already closed, the servlet response OutputStream has been aborted by the client, or the disk/temp directory is full. The parallel forEach on apps combined with synchronized(zipOutputStream) means a single failed write propagates as ServiceException.
Common situations: Client cancels a large export download mid-stream (broken pipe); the portal runs in a container with a small /tmp or low disk quota; an older ZipOutputStream is reused after finish() was called; concurrent export requests sharing a stream.
Related errors
- export app config error
- Write namespace error. {}
- Write error. {}
- export config error
- import configs failed: %s
AI-assisted analysis of apolloconfig/apollo@d95fc18d11 (2026-08-14).
Data as JSON: /api/errors/0d2a4c6c4881ec55.
Report an issue: GitHub.