theonedev/onedev · error · ExplicitException

Unexpected attachment url:

Error message

Unexpected attachment url: 

What it means

Thrown by the YouTrack attachment processor when an attachment URL returned by the YouTrack API does not start with "/api". The importer expects relative API attachment URLs so it can prefix the server base endpoint; an absolute URL or unexpected path means YouTrack's API shape changed or the value is malformed, so it fails fast.

Source

Thrown at server-plugin/server-plugin-import-youtrack/src/main/java/io/onedev/server/plugin/imports/youtrack/ImportServer.java:394

				private String processAttachments(String issueUUID, String readableIssueId, @Nullable String markdown,
												  List<JsonNode> attachmentNodes, Set<String> tooLargeAttachments) {
					if (markdown == null)
						markdown = "";

					Map<String, String> unreferencedAttachments = new LinkedHashMap<>();

					long maxUploadFileSize = OneDev.getInstance(SettingService.class)
							.getPerformanceSetting().getMaxUploadFileSize() * 1L * 1024 * 1024;
					for (JsonNode attachmentNode : attachmentNodes) {
						String attachmentName = attachmentNode.get("name").asText(null);
						String attachmentUrl = attachmentNode.get("url").asText(null);
						long attachmentSize = attachmentNode.get("size").asLong(0);
						if (attachmentSize != 0 && attachmentName != null && attachmentUrl != null) {
							if (attachmentSize > maxUploadFileSize) {
								tooLargeAttachments.add(readableIssueId + ":" + attachmentName);
							} else {
								if (!attachmentUrl.startsWith("/api"))
									throw new ExplicitException("Unexpected attachment url: " + attachmentUrl);
								attachmentUrl = attachmentUrl.substring("/api".length());

								String endpoint = getApiEndpoint(attachmentUrl);
								WebTarget target = client.target(endpoint);
								Invocation.Builder builder = target.request();
								try (Response response = builder.get()) {
									String errorMessage = JerseyUtils.checkStatus(endpoint, response);
									if (errorMessage != null) {
										throw new ExplicitException(String.format(
												"Error downloading attachment (url: %s, error message: %s)",
												endpoint, errorMessage));
									}
									try (InputStream is = response.readEntity(InputStream.class)) {
										AttachmentService attachmentService = OneDev.getInstance(AttachmentService.class);
										String oneDevAttachmentName = attachmentService.saveAttachment(
												oneDevProject.getId(), issueUUID, attachmentName, is);
										String oneDevAttachmentUrl = oneDevProject.getAttachmentUrlPath(issueUUID, oneDevAttachmentName);
										if (markdown.contains("(" + attachmentName + ")")) {

View on GitHub (pinned to d44925c47c)

Solutions

  1. Upgrade or downgrade the YouTrack importer plugin to match your YouTrack server version.
  2. Check YouTrack version — this plugin expects the REST API returning relative /api attachment URLs.
  3. If behind a proxy, ensure the API responses are not rewritten to absolute URLs.
  4. Inspect the attachment JSON to confirm the url field shape and report/mismatch-handling accordingly.

Example fix

// before: absolute url from YouTrack breaks check
"url": "https://youtrack.example.com/api/attachments/1-2"

// after: proxy config preserving relative API url
"url": "/api/attachments/1-2"
Defensive patterns

Strategy: try-catch

Validate before calling

// sanity-check attachment urls before download
for (JsonNode att : attachments) {
    String url = att.path("url").asText(null);
    if (url != null && !url.startsWith("/api"))
        logger.warn("Skipping non-relative attachment url: {}", url);
}

Try / catch

try { processAttachments(...); } catch (ExplicitException e) { logger.error("Attachment url format issue: {}", e.getMessage()); }

Prevention

When it happens

Trigger: YouTrack attachment "url" attribute is an absolute URL (e.g. https://youtrack.example.com/api/attachments/123) or some other path instead of the expected "/api/attachments/..." relative form, e.g. when using a proxy that rewrites URLs or a newer/older YouTrack REST version.

Common situations: YouTrack behind a reverse proxy that emits absolute URLs; YouTrack version upgrade changing the attachments payload; custom YouTrack cloud instance returning full URLs.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/dbe41f290e85d20f. Report an issue: GitHub.