theonedev/onedev · error · ClientException

Attribute not found: ${attributeKey}

Error message

Attribute not found: ${attributeKey}

What it means

getAttribute() throws a ClientException (HTTP 400) when a required metadata attribute is missing or empty in the multipart upload to the PyPI pack endpoint. Helpers name(), version(), and sha256Hash() call it for 'name', 'version', and 'sha256' attributes respectively.

Source

Thrown at server-plugin/server-plugin-pack-pypi/src/main/java/io/onedev/server/plugin/pack/pypi/PypiPackHandler.java:88

		this.packBlobService = packBlobService;
		this.packService = packService;
		this.projectService = projectService;
		this.buildService = buildService;
	}
	
	@Override
	public String getHandlerId() {
		return HANDLER_ID;
	}

	private String getLockName(Long projectId, String name) {
		return "update-pack:" + projectId + ":" + TYPE + ":" + name;
	}
	
	private String getAttribute(Map<String, List<String>> attributes, String attributeKey) {
		var value = attributes.get(attributeKey);
		if (value == null || value.isEmpty())
			throw new ClientException(SC_BAD_REQUEST, "Attribute not found: " + attributeKey);
		return value.get(0);
	}
	
	@Override
	public void handle(HttpServletRequest request, HttpServletResponse response, Long projectId, 
						Long buildId, List<String> pathSegments) {
		var method = request.getMethod();
		
		var isGet = method.equals("GET");
		var isPost = method.equals("POST");
		
		if (pathSegments.isEmpty()) {
			if (isPost) {
				var upload = new ServletFileUpload();
				try {
					var attributes = new LinkedHashMap<String, List<String>>();
					var items = upload.getItemIterator(request);
					while (items.hasNext()) {

View on GitHub (pinned to d44925c47c)

Solutions

  1. Include all required multipart fields in the upload: name, version, sha256 (as form attributes alongside the file).
  2. Verify each field is non-empty and spelled exactly as expected (lowercase keys).
  3. If using a custom script, print the request fields before sending and compare with the handler's expected attributes.

Example fix

// before
curl -F "file=@pkg.whl" http://server/~pypi/...
// after
curl -F "name=mypkg" -F "version=1.0.0" -F "sha256=<digest>" -F "file=@pkg.whl" http://server/~pypi/...
Defensive patterns

Strategy: validation

Validate before calling

required = {'name': name, 'version': version, 'sha256': sha256}
missing = [k for k, v in required.items() if not v]
assert not missing, f'missing upload attributes: {missing}'

Try / catch

if resp.status_code == 400 and 'Attribute not found' in resp.text:
    fix_missing_fields(resp.text.split(':')[-1].strip())

Prevention

When it happens

Trigger: POSTing a package upload where the multipart form is missing the 'name', 'version', or 'sha256' field, or sends it with an empty value; sending fields under different names than the handler expects.

Common situations: A custom CI publish script (curl/wget) that omits required form fields; a misconfigured upload pipeline; using an outdated upload script with old field names after an upgrade.

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/d41cab2119474f0b. Report an issue: GitHub.