theonedev/onedev · error · ClientException

Package file name param is missing

Error message

Package file name param is missing

What it means

The /~pypi/files route requires three segments: package name, version, and file name. When the file name segment is missing (pathSegments.size() < 3 after 'files'), the handler throws ClientException(SC_BAD_REQUEST, "Package file name param is missing") → HTTP 400.

Source

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

								String template = Resources.toString(tplUrl, UTF_8);
								response.setContentType(CONTENT_TYPE_SIMPLE);
								sendResponse(response, evalTemplate(template, bindings));
								response.setStatus(SC_OK);
							} catch (IOException e) {
								throw new RuntimeException(e);
							}
						} else {
							response.setStatus(SC_NOT_FOUND);
						}
					});
				}
			} else if (currentSegment.equals("files")) {
				if (pathSegments.size() < 1)
					throw new ClientException(SC_BAD_REQUEST, "Package name param is missing");
				else if (pathSegments.size() < 2)
					throw new ClientException(SC_BAD_REQUEST, "Package version param is missing");
				else if (pathSegments.size() < 3)
					throw new ClientException(SC_BAD_REQUEST, "Package file name param is missing");
				
				var name = UrlUtils.decodePath(pathSegments.get(0));
				var version = UrlUtils.decodePath(pathSegments.get(1));
				var fileName = UrlUtils.decodePath(pathSegments.get(2));
				
				sessionService.run(() -> {
					var project = checkProject(projectId, false);
					var pack = packService.findByNameAndVersion(project, TYPE, name, version);
					if (pack != null) {
						var data = (PypiData) pack.getData();
						var sha256BlobHash = data.getSha256BlobHashes().get(fileName);
						if (sha256BlobHash != null) {
							PackBlob packBlob;
							if ((packBlob = packBlobService.checkPackBlob(projectId, sha256BlobHash)) != null) {
								response.setContentType(MediaType.APPLICATION_OCTET_STREAM);
								try {
									packBlobService.downloadBlob(packBlob.getProject().getId(),
											packBlob.getSha256Hash(), response.getOutputStream());

View on GitHub (pinned to d44925c47c)

Solutions

  1. Include the exact wheel/sdist file name as the third segment
  2. Resolve the file name from the package-versions index page
  3. Make sure trailing slashes are not creating/losing empty segments
  4. Quote URLs in scripts so special characters don't break path parsing

Example fix

// before
GET /myproj/~pypi/files/mypkg/1.0.0/
// after
GET /myproj/~pypi/files/mypkg/1.0.0/mypkg-1.0.0-py3-none-any.whl
Defensive patterns

Strategy: validation

Validate before calling

const parts = filesUrl.split('/').filter(Boolean);
if (parts.length < 3 || !parts[parts.length-1].match(/\.(whl|tar\.gz|zip|tar\.bz2)$/)) {
  throw new Error('File name segment missing or not a package artifact: ' + filesUrl);
}

Try / catch

try {
  const r = await fetch(filesUrl);
  if (r.status === 400) throw new Error('Missing URL segment: ' + await r.text());
} catch (e) { console.error(e); }

Prevention

When it happens

Trigger: GET /~pypi/files/<name>/<version> without the final file name segment (PypiPackHandler.java:245-246).

Common situations: Version-level listing links confused with file download links; scripts building URLs with empty file names; URL normalization stripping the last empty segment (trailing slash).

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