theonedev/onedev · error · BadRequestException
Invalid http method for blob pull: ${method}
Error message
Invalid http method for blob pull: ${method} What it means
The blob pull endpoint supports GET, HEAD, and (explicitly rejected) DELETE; any other method is rejected with this BadRequestException. DELETE on a blob returns 405 UNSUPPORTED. This guards the read-only nature of the blob resource beyond the method-not-allowed path.
Source
Thrown at server-plugin/server-plugin-pack-container/src/main/java/io/onedev/server/plugin/pack/container/ContainerServlet.java:271
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);
}
});
if (method.equals("GET")) {
packBlobService.downloadBlob(packBlobInfo.getLeft(), packBlobInfo.getRight(),
response.getOutputStream());
}
} else if (method.equals("DELETE")) {
throw new ClientException(SC_METHOD_NOT_ALLOWED, ErrorCode.UNSUPPORTED);
} else {
throw new BadRequestException("Invalid http method for blob pull: " + method);
}
} else if ((matcher = compile("(.+)/([^/]+)/manifests/([^/]+)").matcher(pathInfo)).matches()) {
var projectPath = matcher.group(1);
var repository = matcher.group(2);
var reference = matcher.group(3);
switch (method) {
case "PUT":
var projectId = sessionService.call(() -> checkProject(projectPath, true).getId());
var baos = new ByteArrayOutputStream();
try (var is = request.getInputStream()) {
var copied = copyWithMaxSize(is, baos, MAX_MANIFEST_SIZE);
if (copied == -1)
throw new ClientException(SC_NOT_ACCEPTABLE, ErrorCode.DENIED, "Manifest exceeds maximum size: " + MAX_MANIFEST_SIZE);
}
var bytes = baos.toByteArray();
String hash;
if (isTag(reference)) {View on GitHub (pinned to d44925c47c)
Solutions
- Upload blobs via POST /v2/<name>/blobs/uploads/ then PATCH/PUT on the returned session URL; never PUT to /blobs/<digest>.
- Fetch blobs with GET (or HEAD for existence checks) on /v2/<name>/blobs/<digest>.
- Do not attempt DELETE on blobs; blobs are garbage-collected server-side.
- Update the client to this registry's supported method set (GET/HEAD for pull).
Example fix
// before PUT /v2/app/blobs/sha256:abc... body=@layer.tgz // after loc = POST /v2/app/blobs/uploads/ -> Location PATCH loc (chunk) ; PUT loc?digest=sha256:abc...
Defensive patterns
Strategy: validation
Validate before calling
if (!['GET','HEAD'].includes(method)) {
throw new Error(`Blob pull supports GET/HEAD only, got ${method}`);
} Prevention
- Pull blobs with GET, check existence with HEAD.
- Never use PUT on /blobs/<digest>; use the POST-initiated upload session flow.
- Do not attempt DELETE on blobs; rely on server-side GC.
- Audit client method/URL templates against the OCI distribution spec.
When it happens
Trigger: Any method other than GET or HEAD sent to /v2/<name>/blobs/<digest> — e.g. PUT attempting to push a blob at its final URL, POST, or OPTIONS. PUT on the blob URL is a common mistake because some registries tolerate monolithic PUT; OneDev requires the POST-initiated upload flow.
Common situations: Clients implementing the monolithic PUT upload variant (POST then PUT to /blobs/<digest>) which this registry does not support; generic REST clients defaulting to POST; tooling probing the blob endpoint with OPTIONS.
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
- Invalid http method for blob upload: ${method}
- Invalid http method for manifest pull: ${method}
- Invalid value '${value}' for ${type} '${name}'. Valid values
- Access token owner should have permission to manage authoriz
- Should only disable normal users
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/024166b50f261654.
Report an issue: GitHub.