{"record":{"id":"92cbd7d49d210922","repo":"theonedev/onedev","slug":"parameter-attachment-group-has-to-be-specified","errorCode":null,"errorMessage":"Parameter 'attachment-group' has to be specified","messagePattern":"Parameter 'attachment-group' has to be specified","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/web/resource/AttachmentResource.java","lineNumber":66,"sourceCode":"\tprivate static final long serialVersionUID = 1L;\n\n\tprivate static final String PARAM_PROJECT = \"project\";\n\t\n\tprivate static final String PARAM_ATTACHMENT_GROUP = \"attachment-group\";\n\t\n\tprivate static final String PARAM_ATTACHMENT = \"attachment\";\n\t\n\tpublic static final String PARAM_AUTHORIZATION = \"authorization\";\n\t\n\t@Override\n\tprotected ResourceResponse newResourceResponse(Attributes attributes) {\n\t\tPageParameters params = attributes.getParameters();\n\t\t\n\t\tLong projectId = params.get(PARAM_PROJECT).toLong();\n\t\tString attachmentGroup = params.get(PARAM_ATTACHMENT_GROUP).toString();\n\t\t\n\t\tif (StringUtils.isBlank(attachmentGroup))\n\t\t\tthrow new IllegalArgumentException(\"Parameter 'attachment-group' has to be specified\");\n\t\telse if (attachmentGroup.contains(\"..\"))\n\t\t\tthrow new IllegalArgumentException(\"Invalid parameter 'attachment-group'\");\n\n\t\tif (!SecurityUtils.isSystem()) {\n\t\t\tProject project = OneDev.getInstance(ProjectService.class).load(projectId);\n\t\t\t\n\t\t\tString authorization = params.get(PARAM_AUTHORIZATION).toOptionalString();\n\t\t\tif (authorization == null \n\t\t\t\t\t|| !new String(CryptoUtils.decrypt(Base64.decodeBase64(authorization)), UTF_8).equals(attachmentGroup)) {\n\t\t\t\tIssue issue;\n\t\t\t\tBuild build;\n\t\t\t\tif (OneDev.getInstance(PullRequestService.class).find(attachmentGroup) != null\n\t\t\t\t\t\t|| OneDev.getInstance(CodeCommentService.class).findByUUID(attachmentGroup) != null) {\n\t\t\t\t\tif (!SecurityUtils.canReadCode(project))\n\t\t\t\t\t\tthrow new UnauthorizedException();\n\t\t\t\t} else if ((issue = OneDev.getInstance(IssueService.class).find(attachmentGroup)) != null) {\n\t\t\t\t\tif (!SecurityUtils.canAccessIssue(issue))\n\t\t\t\t\t\tthrow new UnauthorizedException();","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/web/resource/AttachmentResource.java#L48-L84","documentation":"AttachmentResource serves files attached to issue/PR/code-comment/build attachment groups. It reads the 'attachment-group' query parameter and throws IllegalArgumentException when it is blank, since the group determines which entity's attachments to look in and is needed for authorization.","triggerScenarios":"Requesting an attachment URL (~/.attachments/...) without the attachment-group parameter, or with it set to an empty string.","commonSituations":"Building the URL manually and omitting the group; a template variable for the group left empty (e.g. undefined issue key/UUID); stripping query params behind a proxy.","solutions":["Include attachment-group=<group> (issue number, PR key, code comment UUID, or build number depending on origin) in the URL","If the group comes from a variable, check it is populated before forming the URL","Copy a working attachment link from the OneDev UI and adapt only the attachment file name"],"exampleFix":"// before\nGET /~resources/attachment?project=1&attachment=log.txt\n// after\nGET /~resources/attachment?project=1&attachment-group=42&attachment=log.txt","handlingStrategy":"validation","validationCode":"if (!attachmentGroup || !String(attachmentGroup).trim()) throw new Error('attachment-group is required (issue number, PR key, comment UUID, or build number)');\nconst url = `~/.attachment?project=${projectId}&attachment-group=${encodeURIComponent(attachmentGroup)}&attachment=${encodeURIComponent(name)}`;","typeGuard":"function hasAttachmentGroup(g) { return typeof g === 'string' && g.trim().length > 0; }","tryCatchPattern":null,"preventionTips":["Always pass attachment-group when fetching attachments","Check group variables are set before URL construction","Derive group values from the entity context (issue, PR, build) programmatically"],"tags":["http","missing-parameter","attachment"],"backgroundTag":"missing-required-argument","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}