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
- Include all required multipart fields in the upload: name, version, sha256 (as form attributes alongside the file).
- Verify each field is non-empty and spelled exactly as expected (lowercase keys).
- 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
- Keep the upload field names in sync with the handler (name, version, sha256).
- Validate form data client-side before sending.
- Review upload scripts when upgrading OneDev.
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
- Content disposition header not found in uploaded file
- File name not found in content disposition header of uploade
- File length incorrect:
- Digest mismatch
- Title is required
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/d41cab2119474f0b.
Report an issue: GitHub.