theonedev/onedev · error · ClientException

Package version param is missing

Error message

Package version param is missing

What it means

The /~pypi/files download route requires name, version, and file name segments. With only the name supplied (pathSegments.size() < 2 after 'files'), the handler throws ClientException(SC_BAD_REQUEST, "Package version 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:244

							try {
								URL tplUrl = Resources.getResource(getClass(), "package-versions.tpl");
								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 {

View on GitHub (pinned to d44925c47c)

Solutions

  1. Append both version and file name: /~pypi/files/<name>/<version>/<fileName>
  2. Get the exact link from the package's simple index page
  3. Verify variables feeding URL templates are non-empty
  4. Check for encoders/proxies that drop path segments

Example fix

// before
GET /myproj/~pypi/files/mypkg
// 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 segments = filesUrl.split('/').filter(Boolean).slice(-3);
if (segments.length < 3) throw new Error('Download URL must end with <name>/<version>/<fileName>, got: ' + filesUrl);

Try / catch

try {
  const r = await fetch(filesUrl);
  if (r.status === 400) throw new Error('Bad /files request: ' + await r.text());
} catch (e) { console.error('Check URL completeness:', e); }

Prevention

When it happens

Trigger: GET /~pypi/files/<name> with no version and file name segments (PypiPackHandler.java:243-244).

Common situations: URL truncation when a link is cut at a slash; template or script interpolating an empty version; manual construction of download URLs.

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