apolloconfig/apollo · error · ServiceException

Write error. {}

Error message

Write error. {}

What it means

Thrown by ConfigsExportService.writeClusterInfoToZip() when serializing a ClusterDTO to JSON and writing it as a ZipEntry fails with an IOException. The cluster consumer iterates over exportClusters, generates a cluster-info file path, and calls writeToZip inside a synchronized block on the ZipOutputStream. A single IOException aborts the whole cluster export via ServiceException.

Source

Thrown at apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ConfigsExportService.java:325

      }
    };

    configBOStream.forEach(configBOConsumer);
  }

  private void writeClusterInfoToZip(Env env, App app, List<ClusterDTO> exportClusters,
      ZipOutputStream zipOutputStream) {
    final Consumer<ClusterDTO> clusterConsumer = cluster -> {
      try {
        synchronized (zipOutputStream) {
          String fileName = ConfigFileUtils.genClusterInfoPath(app, env, cluster);
          String content = gson.toJson(cluster);

          writeToZip(fileName, content, zipOutputStream);
        }
      } catch (IOException e) {
        logger.error("Write error. {}", cluster);
        throw new ServiceException("Write error. {}", e);
      }
    };

    exportClusters.forEach(clusterConsumer);
  }

  private void writeToZip(String filePath, String content, ZipOutputStream zipOutputStream)
      throws IOException {
    final ZipEntry zipEntry = new ZipEntry(filePath);
    try {
      zipOutputStream.putNextEntry(zipEntry);
      zipOutputStream.write(content.getBytes());
      zipOutputStream.closeEntry();
    } catch (IOException e) {
      String errorMsg = "write content to zip error. file = " + filePath + ", content = " + content;
      logger.error(errorMsg);
      throw new IOException(errorMsg, e);
    }

View on GitHub (pinned to d95fc18d11)

Solutions

  1. Review portal logs for the 'Write error. {cluster}' line to identify the failing ClusterDTO and the IOException cause.
  2. Confirm the export ZipOutputStream lifecycle: it must remain open until all consumers (app, namespace, cluster) finish.
  3. Check server disk space and client connection stability during large multi-cluster exports.
  4. Ensure exportClusters is not invoked on an already-finished or closed stream from a prior failed export stage.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  configsExportService.writeClusterInfoToZip(env, app, clusters, zipOutputStream);
} catch (ServiceException e) {
  log.error("Cluster info write to zip failed", e);
  throw e;
}

Prevention

When it happens

Trigger: Exporting cluster metadata where writeToZip() encounters a closed/finished ZipOutputStream, a client-disconnected response stream, or a disk-full condition. The synchronized block ensures thread safety but any I/O failure inside it throws and propagates out of forEach.

Common situations: Client cancels the export download; portal container disk full; ZipOutputStream.finish() invoked early by a prior error handler; concurrent export of the same env producing interleaved close/write.

Related errors


AI-assisted analysis of apolloconfig/apollo@d95fc18d11 (2026-08-14). Data as JSON: /api/errors/a4ff1afdc404d895. Report an issue: GitHub.