theonedev/onedev · error · IllegalArgumentException

Parameter 'attachment-group' has to be specified

Error message

Parameter 'attachment-group' has to be specified

What it means

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.

Source

Thrown at server-core/src/main/java/io/onedev/server/web/resource/AttachmentResource.java:66

	private static final long serialVersionUID = 1L;

	private static final String PARAM_PROJECT = "project";
	
	private static final String PARAM_ATTACHMENT_GROUP = "attachment-group";
	
	private static final String PARAM_ATTACHMENT = "attachment";
	
	public static final String PARAM_AUTHORIZATION = "authorization";
	
	@Override
	protected ResourceResponse newResourceResponse(Attributes attributes) {
		PageParameters params = attributes.getParameters();
		
		Long projectId = params.get(PARAM_PROJECT).toLong();
		String attachmentGroup = params.get(PARAM_ATTACHMENT_GROUP).toString();
		
		if (StringUtils.isBlank(attachmentGroup))
			throw new IllegalArgumentException("Parameter 'attachment-group' has to be specified");
		else if (attachmentGroup.contains(".."))
			throw new IllegalArgumentException("Invalid parameter 'attachment-group'");

		if (!SecurityUtils.isSystem()) {
			Project project = OneDev.getInstance(ProjectService.class).load(projectId);
			
			String authorization = params.get(PARAM_AUTHORIZATION).toOptionalString();
			if (authorization == null 
					|| !new String(CryptoUtils.decrypt(Base64.decodeBase64(authorization)), UTF_8).equals(attachmentGroup)) {
				Issue issue;
				Build build;
				if (OneDev.getInstance(PullRequestService.class).find(attachmentGroup) != null
						|| OneDev.getInstance(CodeCommentService.class).findByUUID(attachmentGroup) != null) {
					if (!SecurityUtils.canReadCode(project))
						throw new UnauthorizedException();
				} else if ((issue = OneDev.getInstance(IssueService.class).find(attachmentGroup)) != null) {
					if (!SecurityUtils.canAccessIssue(issue))
						throw new UnauthorizedException();

View on GitHub (pinned to d44925c47c)

Solutions

  1. Include attachment-group=<group> (issue number, PR key, code comment UUID, or build number depending on origin) in the URL
  2. If the group comes from a variable, check it is populated before forming the URL
  3. Copy a working attachment link from the OneDev UI and adapt only the attachment file name

Example fix

// before
GET /~resources/attachment?project=1&attachment=log.txt
// after
GET /~resources/attachment?project=1&attachment-group=42&attachment=log.txt
Defensive patterns

Strategy: validation

Validate before calling

if (!attachmentGroup || !String(attachmentGroup).trim()) throw new Error('attachment-group is required (issue number, PR key, comment UUID, or build number)');
const url = `~/.attachment?project=${projectId}&attachment-group=${encodeURIComponent(attachmentGroup)}&attachment=${encodeURIComponent(name)}`;

Type guard

function hasAttachmentGroup(g) { return typeof g === 'string' && g.trim().length > 0; }

Prevention

When it happens

Trigger: Requesting an attachment URL (~/.attachments/...) without the attachment-group parameter, or with it set to an empty string.

Common situations: 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.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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