theonedev/onedev · error · ClientException

File name not found in content disposition header of uploade

Error message

File name not found in content disposition header of uploaded file

What it means

The handler parses the Content-Disposition header of the uploaded file part to extract the filename= parameter. If the header exists but contains no filename field (or it is empty), a ClientException (HTTP 400) is thrown.

Source

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

								attributes.remove("blake2_256_digest");
								attributes.remove(":action");
								attributes.remove("protocol_version");
								
								LockUtils.run(getLockName(projectId, name), () -> transactionService.run(() -> {
									var project = checkProject(projectId, true);
									var contentDisposition = item.getHeaders().getHeader("content-disposition"); 
									if (contentDisposition == null)
										throw new ClientException(SC_BAD_REQUEST, "Content disposition header not found in uploaded file");
									String fileName = null;
									for (var field: Splitter.on(";").omitEmptyStrings().trimResults().split(contentDisposition)) {
										if (field.startsWith("filename=")) {
											fileName = field.substring("filename=".length() + 1);
											fileName = fileName.substring(0, fileName.length() - 1);
											break;
										}
									}
									if (fileName == null) 
										throw new ClientException(SC_BAD_REQUEST, "File name not found in content disposition header of uploaded file");

									var packBlobId = packBlobService.uploadBlob(projectId, is, sha256Hash);																																								
									if (packBlobId == null)
										throw new ClientException(SC_BAD_REQUEST, "Digest mismatch");
									
									PypiData data;
									var pack = packService.findByNameAndVersion(project, TYPE, name, version);
									if (pack == null) {
										pack = new Pack();
										pack.setType(TYPE);
										pack.setName(name);
										pack.setVersion(version);
										pack.setProject(project);
										data = new PypiData(attributes, new LinkedHashMap<>());
										pack.setData(data);
									} else {
										data = (PypiData) pack.getData();
									}

View on GitHub (pinned to d44925c47c)

Solutions

  1. Ensure the file part includes filename= in its Content-Disposition: curl -F "file=@actual-file.whl" does this automatically.
  2. If constructing the request manually, add filename="pkg.whl" to the part header.
  3. Log/inspect the Content-Disposition header of the failing request to confirm what the client actually sent.

Example fix

// before
Content-Disposition: form-data; name="file"
// after
Content-Disposition: form-data; name="file"; filename="mypkg-1.0.0-py3-none-any.whl"
Defensive patterns

Strategy: validation

Validate before calling

# ensure filename is included in the file part
files = {'file': ('pkg-1.0.0.whl', fh)}  # explicit tuple with filename

Try / catch

if resp.status_code == 400 and 'File name not found' in resp.text:
    raise RuntimeError('Add filename= to the multipart part')

Prevention

When it happens

Trigger: Multipart file part with a Content-Disposition like 'form-data; name="file"' but no filename="..." attribute, or an empty filename value.

Common situations: Client libraries that submit form fields without a filename attribute for file parts; template-generated requests where the filename variable is empty; programmatic multipart builders that omit filename.

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