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
- Upgrade or downgrade the YouTrack importer plugin to match your YouTrack server version.
- Check YouTrack version — this plugin expects the REST API returning relative /api attachment URLs.
- If behind a proxy, ensure the API responses are not rewritten to absolute URLs.
- 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
- Test the plugin against your YouTrack version before bulk import.
- Ensure reverse proxies do not rewrite YouTrack API responses to absolute URLs.
- Keep the importer plugin updated for your YouTrack REST version.
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
- Error downloading attachment (url: %s, error message: %s)
- Unable to find YouTrack project:
- No field spec found:
- No link spec found:
- Duplicate issue field mapping (issue: %s, field: %s)
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/dbe41f290e85d20f.
Report an issue: GitHub.