theonedev/onedev · error · BadRequestException
Invalid http method for manifest pull: ${method}
Error message
Invalid http method for manifest pull: ${method} What it means
The manifest endpoint supports GET/HEAD (pull), PUT (push), and DELETE (remove by tag); any other method falls through to this BadRequestException. The message is phrased for the pull path but applies to any unsupported method on /v2/<name>/manifests/<reference>.
Source
Thrown at server-plugin/server-plugin-pack-container/src/main/java/io/onedev/server/plugin/pack/container/ContainerServlet.java:430
packBlobService.downloadBlob(manifestInfo.getLeft(), manifestInfo.getRight(), baos);
bytes = baos.toByteArray();
response.setContentType(new ContainerManifest(bytes).getMediaType());
if (method.equals("GET"))
response.getOutputStream().write(bytes);
} else {
throw new NotFoundException(ErrorCode.MANIFEST_UNKNOWN);
}
break;
case "DELETE":
sessionService.run(() -> {
var project = checkProject(projectPath, true);
if (isTag(reference))
packService.deleteByNameAndVersion(project, TYPE, repository, reference);
response.setStatus(SC_ACCEPTED);
});
break;
default:
throw new BadRequestException("Invalid http method for manifest pull: " + method);
}
} else if ((matcher = compile("(.+)/([^/]+)/tags/list").matcher(pathInfo)).matches()) {
var projectPath = matcher.group(1);
var repository = matcher.group(2);
sessionService.run(() -> {
var project = checkProject(projectPath, false);
var result = new HashMap<String, Object>();
result.put("name", projectPath + "/" + repository);
var tags = new ArrayList<String>();
result.put("tags", tags);
int count = Integer.MAX_VALUE;
var countParam = request.getParameter("n");
if (countParam != null)
count = Integer.parseInt(countParam);
if (count != 0) {
var lastTag = request.getParameter("last");View on GitHub (pinned to d44925c47c)
Solutions
- Pull with GET (or HEAD), push with PUT, delete with DELETE on /v2/<name>/manifests/<reference>.
- Replace POST/PATCH usage with a full PUT of the complete manifest.
- Note DELETE only works by tag; deleting by digest is not supported here — delete via tag or prune server-side.
- Fix client URL/method mapping for the OCI distribution API.
Example fix
// before POST /v2/app/manifests/1.0 body=manifest.json // after PUT /v2/app/manifests/1.0 body=manifest.json
Defensive patterns
Strategy: validation
Validate before calling
const MANIFEST_METHODS = ['GET','HEAD','PUT','DELETE'];
if (!MANIFEST_METHODS.includes(method)) {
throw new Error(`/manifests/ accepts GET/HEAD/PUT/DELETE only, got ${method}`);
} Prevention
- Full-manifest PUT instead of POST/PATCH-style updates.
- Delete manifests by tag only.
- Keep client method/URL mapping aligned with the OCI distribution API.
- Ignore OPTIONS preflight noise from scanners; it is unsupported by design.
When it happens
Trigger: Methods other than GET/HEAD/PUT/DELETE sent to /v2/<name>/manifests/<reference> — e.g. POST to the manifests URL, PATCH attempting partial manifest updates, or OPTIONS from preflight scanners.
Common situations: Clients using POST-based creation (some generic REST wrappers); tooling attempting PATCH-style manifest editing, which OCI does not allow; security probes hitting the manifests route.
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 blob pull: ${method}
- DENIED
- Invalid value '${value}' for ${type} '${name}'. Valid values
- Access token owner should have permission to manage authoriz
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/7d989f34dcd5a1f0.
Report an issue: GitHub.