theonedev/onedev · error · BadRequestException

Invalid http method for blob upload: ${method}

Error message

Invalid http method for blob upload: ${method}

What it means

The blob-upload endpoint only supports POST (initiate), PATCH (chunk), PUT (finalize), GET (status), and DELETE (cancel). Any other HTTP method on /v2/<name>/blobs/uploads/<uuid> is rejected with a BadRequestException carrying this message. It indicates the client is calling the upload resource incorrectly.

Source

Thrown at server-plugin/server-plugin-pack-container/src/main/java/io/onedev/server/plugin/pack/container/ContainerServlet.java:243

						}
						break;
					}
					case "GET": {
						var uploadedSize = packBlobService.getUploadFileSize(projectId, uuid);
						if (uploadedSize == -1)
							throw new NotFoundException(ErrorCode.BLOB_UPLOAD_UNKNOWN);
						response.setStatus(SC_NO_CONTENT);
						response.setHeader("Range", "0-" + (uploadedSize - 1));
						response.setHeader("Docker-Upload-UUID", uuid);
						break;
					}
					case "DELETE": {
						packBlobService.cancelUpload(projectId, uuid);
						response.setStatus(SC_NO_CONTENT);
						break;
					}
					default: {
						throw new BadRequestException("Invalid http method for blob upload: " + method);
					}
				}
			} else if ((matcher = compile("(.+)/([^/]+)/blobs/([^/]+)").matcher(pathInfo)).matches()) {
				var projectPath = matcher.group(1);
				var digestString = matcher.group(3);
				if (method.equals("GET") || method.equals("HEAD")) {
					var packBlobInfo = sessionService.call(() -> {
						var project = checkProject(projectPath, false);
						var digest = parseDigest(digestString);
						var hash = digest.getHash();
						PackBlob packBlob;
						if ((packBlob = packBlobService.checkPackBlob(project.getId(), hash)) != null) {
							response.setStatus(SC_OK);	
							response.setHeader("Content-Length", String.valueOf(packBlob.getSize()));
							response.setHeader("Docker-Content-Digest", digestString);
							return new Pair<>(packBlob.getProject().getId(), packBlob.getSha256Hash());
						} else {
							throw new NotFoundException(ErrorCode.BLOB_UNKNOWN);

View on GitHub (pinned to d44925c47c)

Solutions

  1. Use POST .../blobs/uploads/ to initiate, PATCH to append chunks, and PUT ...?digest= to finalize.
  2. Use GET .../blobs/<digest> (not the upload URL) to check whether a blob exists.
  3. Use HEAD .../blobs/<digest> for existence checks; the upload session does not support it.
  4. Fix the client's URL construction so upload-session and blob-fetch URLs are not mixed up.

Example fix

// before
PUT /v2/app/blobs/uploads/<uuid>            # wrong resource
// after
PUT /v2/app/blobs/uploads/<uuid>?digest=sha256:...   # finalize, or
GET /v2/app/blobs/sha256:...                # fetch existing blob
Defensive patterns

Strategy: validation

Validate before calling

const UPLOAD_METHODS = ['POST','PATCH','PUT','GET','DELETE'];
if (!UPLOAD_METHODS.includes(method)) {
  throw new Error(`Use POST/PATCH/PUT/GET/DELETE on blobs/uploads URLs, got ${method}`);
}

Prevention

When it happens

Trigger: Any method other than POST/PATCH/PUT/GET/DELETE sent to a URL matching (.+)/([^/]+)/blobs/uploads/([^/]+), e.g. a PUT directly to the session URL without digest, HEAD on the upload session, or a scanner/probe hitting the upload path with OPTIONS.

Common situations: Custom clients confusing the upload session URL with the blob URL (PUT to uploads/... instead of .../blobs/<digest>); security scanners probing registry endpoints; mis-wired API wrappers calling the wrong URL template.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/5fb6cf0dac26ce0c. Report an issue: GitHub.