{"record":{"id":"1a21fee643b4427e","repo":"theonedev/onedev","slug":"error-downloading-attachment-url-s-error-messa","errorCode":null,"errorMessage":"Error downloading attachment (url: %s, error message: %s)","messagePattern":"Error downloading attachment \\(url: (.+?), error message: (.+?)\\)","errorType":"exception","errorClass":"ExplicitException","httpStatus":null,"severity":"error","filePath":"server-plugin/server-plugin-import-jiracloud/src/main/java/io/onedev/server/plugin/imports/jiracloud/ImportServer.java","lineNumber":807,"sourceCode":"\t\t\t\t\t\tif (!dryRun) { \n\t\t\t\t\t\t\tList<String> attachments = new ArrayList<>();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (fieldsNode.hasNonNull(\"attachment\")) {\n\t\t\t\t\t\t\t\tlong maxUploadFileSize = OneDev.getInstance(SettingService.class)\n\t\t\t\t\t\t\t\t\t\t.getPerformanceSetting().getMaxUploadFileSize()*1L*1024*1024; \n\t\t\t\t\t\t\t\tfor (JsonNode attachmentNode: fieldsNode.get(\"attachment\")) {\n\t\t\t\t\t\t\t\t\tString attachmentName = attachmentNode.get(\"filename\").asText();\n\t\t\t\t\t\t\t\t\tint attachmentSize = attachmentNode.get(\"size\").asInt();\n\t\t\t\t\t\t\t\t\tif (attachmentSize >  maxUploadFileSize) {\n\t\t\t\t\t\t\t\t\t\ttooLargeAttachments.add(issueKey + \":\" + attachmentName);\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tString endpoint = attachmentNode.get(\"content\").asText();\n\t\t\t\t\t\t\t\t\t\tWebTarget target = client.target(endpoint);\n\t\t\t\t\t\t\t\t\t\tInvocation.Builder builder =  target.request();\n\t\t\t\t\t\t\t\t\t\ttry (Response response = builder.get()) {\n\t\t\t\t\t\t\t\t\t\t\tString errorMessage = JerseyUtils.checkStatus(endpoint, response);\n\t\t\t\t\t\t\t\t\t\t\tif (errorMessage != null) { \n\t\t\t\t\t\t\t\t\t\t\t\tthrow new ExplicitException(String.format(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"Error downloading attachment (url: %s, error message: %s)\", \n\t\t\t\t\t\t\t\t\t\t\t\t\t\tendpoint, errorMessage));\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\ttry (InputStream is = response.readEntity(InputStream.class)) {\n\t\t\t\t\t\t\t\t\t\t\t\tAttachmentService attachmentService = OneDev.getInstance(AttachmentService.class);\n\t\t\t\t\t\t\t\t\t\t\t\tString oneDevAttachmentName = attachmentService.saveAttachment(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\toneDevProject.getId(), issue.getUUID(), attachmentName, is);\n\t\t\t\t\t\t\t\t\t\t\t\tString oneDevAttachmentUrl = oneDevProject.getAttachmentUrlPath(issue.getUUID(), oneDevAttachmentName);\n\t\t\t\t\t\t\t\t\t\t\t\tattachments.add(\"[\" + oneDevAttachmentName + \"](\" + oneDevAttachmentUrl + \")\");\n\t\t\t\t\t\t\t\t\t\t\t} catch (IOException e) {\n\t\t\t\t\t\t\t\t\t\t\t\tthrow new RuntimeException(e);\n\t\t\t\t\t\t\t\t\t\t\t} \n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (!attachments.isEmpty()) {","sourceCodeStart":789,"sourceCodeEnd":825,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-plugin/server-plugin-import-jiracloud/src/main/java/io/onedev/server/plugin/imports/jiracloud/ImportServer.java#L789-L825","documentation":"While importing issue attachments, consume() downloads each attachment's content URL with the JAX-RS client and validates the HTTP response via JerseyUtils.checkStatus(). If the response status is not successful, checkStatus returns an error message and the import throws this ExplicitException embedding both the URL and the message, aborting the import.","triggerScenarios":"consume() -> for each attachment, GET attachmentNode.get(\"content\") returns a non-2xx response (401/403/404, expired URL, redirect to an HTML login page), so JerseyUtils.checkStatus yields a non-null errorMessage and the ExplicitException is thrown at line 807.","commonSituations":"Jira attachment URLs require an authenticated session/token that the plain GET does not carry; attachment deleted in Jira after issue listing (404); Jira restricts anonymous downloads; large attachments hitting a proxy/gateway error; network/CDN issues with Atlassian media URLs.","solutions":["Verify the Jira API credentials used by the import have permission to download attachments from the listed content URLs.","Check the reported URL manually (curl) to see the actual status — if 404, the attachment is gone and must be excluded or restored in Jira.","Ensure the Jira base URL is reachable from the OneDev server (no proxy/firewall stripping auth or blocking media CDN hosts).","Retry the import for transient gateway/CDN errors; if a specific attachment is permanently broken, remove it in Jira and re-run."],"exampleFix":"// before: plain unauthenticated GET to content URL fails with 403\nWebTarget target = client.target(endpoint);\n// after: ensure client is built with the auth filter used by newClient()\nClient client = newClient(); // registers bearer token for media downloads\nWebTarget target = client.target(endpoint);","handlingStrategy":"retry","validationCode":"try (Response r = client.target(attachmentUrl).request().get()) {\n    if (r.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL)\n        throw new IllegalStateException(\"Attachment not downloadable: \" + r.getStatus());\n}","typeGuard":null,"tryCatchPattern":"try { importServer.doImport(...) } catch (ExplicitException e) { if (e.getMessage().startsWith(\"Error downloading attachment\")) { /* check URL/status in message, verify credentials, retry */ } }","preventionTips":["Verify token attachment-download permissions before large imports.","Pre-check attachment content URLs for 403/404.","Import from a network path that can reach Atlassian media/CDN hosts.","Retry transient failures; remove permanently broken attachments in Jira."],"tags":["import","jira-cloud","attachment","http","download"],"backgroundTag":"http-error-response","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}