{"record":{"id":"2f7072d79c040f01","repo":"apolloconfig/apollo","slug":"export-items-failed","errorCode":null,"errorMessage":"export items failed:{}","messagePattern":"export items failed:(.+?)","errorType":"exception","errorClass":"ServiceException","httpStatus":500,"severity":"error","filePath":"apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ConfigsExportController.java","lineNumber":111,"sourceCode":"\n    // properties file or public namespace has not suffix (.properties)\n    if (fileNameSplit.size() <= 1\n        || !ConfigFileFormat.isValidFormat(fileNameSplit.get(fileNameSplit.size() - 1))) {\n      fileName = Joiner.on(\".\").join(namespaceName, ConfigFileFormat.Properties.getValue());\n    }\n\n    NamespaceBO namespaceBO = namespaceService.loadNamespaceBO(appId, Env.valueOf(env), clusterName,\n        namespaceName, true, false);\n\n    // generate a file.\n    res.setHeader(HttpHeaders.CONTENT_DISPOSITION, \"attachment;filename=\" + fileName);\n    // file content\n    final String configFileContent = NamespaceBOUtils.convert2configFileContent(namespaceBO);\n    try {\n      // write content to net\n      res.getOutputStream().write(configFileContent.getBytes());\n    } catch (Exception e) {\n      throw new ServiceException(\"export items failed:{}\", e);\n    }\n  }\n\n  /**\n   * Export all configs in a compressed file. Just export namespace which current exists read permission. The permission\n   * check in service.\n   */\n  @PreAuthorize(value = \"@unifiedPermissionValidator.isSuperAdmin()\")\n  @GetMapping(\"/configs/export\")\n  public void exportAll(@RequestParam(value = \"envs\") String envs, HttpServletRequest request,\n      HttpServletResponse response) throws IOException {\n    // filename must contain the information of time\n    final String filename =\n        \"apollo_config_export_\" + DateFormatUtils.format(new Date(), \"yyyy_MMdd_HH_mm_ss\") + \".zip\";\n    // log who download the configs\n    logger.info(\"Download configs, remote addr [{}], remote host [{}]. Filename is [{}]\",\n        request.getRemoteAddr(), request.getRemoteHost(), filename);\n    // set downloaded filename","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/apolloconfig/apollo/blob/d95fc18d112589efc09ddcbe1507047584d55251/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ConfigsExportController.java#L93-L129","documentation":"ServiceException (HTTP 500) from ConfigsExportController single-namespace export when writing the generated config file content to the HttpServletResponse output stream fails. Note the constructor used is ServiceException(String, Exception), so the '{}' in 'export items failed:{}' is NOT formatted (it is Guava-agnostic); the caught Exception is attached as the cause and is where the real detail lives.","triggerScenarios":"GET /apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/export (single-file export) when res.getOutputStream().write(bytes) throws — client disconnected, broken pipe, container I/O error, or the response is already committed.","commonSituations":"User cancels the download mid-stream (ClientAbortException); a proxy/load-balancer timing out and closing the connection; the namespace is large and the socket drops; response already committed by a filter.","solutions":["Read the attached cause Exception in the portal log (it is the real failure, not the '{}' placeholder).","If it is ClientAbortException / broken pipe, treat as benign (the client left) and add a client-disconnect check before writing.","Verify the connection/proxy timeouts are large enough for big namespaces.","Avoid committing the response before the controller writes (no early flush)."],"exampleFix":"// before: any I/O failure becomes a 500 ServiceException\ntry {\n  res.getOutputStream().write(configFileContent.getBytes());\n} catch (Exception e) {\n  throw new ServiceException(\"export items failed:{}\", e);\n}\n\n// after: distinguish a client abort from a real failure, and fix the placeholder\ntry {\n  res.getOutputStream().write(configFileContent.getBytes());\n} catch (ClientAbortException e) {\n  log.warn(\"client aborted export for {}\", fileName);\n} catch (IOException e) {\n  throw new ServiceException(\"export items failed for %s\", e, fileName);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Export can 500 on client disconnect or backend I/O failure.\ntry {\n  portal.exportNamespace(appId, env, cluster, namespace); // downloads file\n} catch (HttpServerErrorException e) {\n  String body = e.getResponseBodyAsString();\n  if (body.contains(\"export items failed\")) {\n    // most often a dropped connection; retry once, or surface 'download failed'\n    log.warn(\"namespace export failed, possible client disconnect: {}\", body);\n  }\n  throw e;\n}","preventionTips":["Treat export 500 as transient for client-disconnect cases; retry once.","Read the cause in portal logs for persistent failures.","Use a longer proxy/read timeout for large namespaces.","Do not pre-commit the HTTP response in filters."],"tags":["export","io","http-response","service-error","client-disconnect"],"backgroundTag":null,"analyzedSha":"d95fc18d112589efc09ddcbe1507047584d55251","analyzedAt":"2026-08-14T04:00:05.477Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}