{"record":{"id":"5fb6cf0dac26ce0c","repo":"theonedev/onedev","slug":"invalid-http-method-for-blob-upload-method","errorCode":null,"errorMessage":"Invalid http method for blob upload: ${method}","messagePattern":"Invalid http method for blob upload: (.+?)","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server-plugin/server-plugin-pack-container/src/main/java/io/onedev/server/plugin/pack/container/ContainerServlet.java","lineNumber":243,"sourceCode":"\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"GET\": {\n\t\t\t\t\t\tvar uploadedSize = packBlobService.getUploadFileSize(projectId, uuid);\n\t\t\t\t\t\tif (uploadedSize == -1)\n\t\t\t\t\t\t\tthrow new NotFoundException(ErrorCode.BLOB_UPLOAD_UNKNOWN);\n\t\t\t\t\t\tresponse.setStatus(SC_NO_CONTENT);\n\t\t\t\t\t\tresponse.setHeader(\"Range\", \"0-\" + (uploadedSize - 1));\n\t\t\t\t\t\tresponse.setHeader(\"Docker-Upload-UUID\", uuid);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"DELETE\": {\n\t\t\t\t\t\tpackBlobService.cancelUpload(projectId, uuid);\n\t\t\t\t\t\tresponse.setStatus(SC_NO_CONTENT);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tthrow new BadRequestException(\"Invalid http method for blob upload: \" + method);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if ((matcher = compile(\"(.+)/([^/]+)/blobs/([^/]+)\").matcher(pathInfo)).matches()) {\n\t\t\t\tvar projectPath = matcher.group(1);\n\t\t\t\tvar digestString = matcher.group(3);\n\t\t\t\tif (method.equals(\"GET\") || method.equals(\"HEAD\")) {\n\t\t\t\t\tvar packBlobInfo = sessionService.call(() -> {\n\t\t\t\t\t\tvar project = checkProject(projectPath, false);\n\t\t\t\t\t\tvar digest = parseDigest(digestString);\n\t\t\t\t\t\tvar hash = digest.getHash();\n\t\t\t\t\t\tPackBlob packBlob;\n\t\t\t\t\t\tif ((packBlob = packBlobService.checkPackBlob(project.getId(), hash)) != null) {\n\t\t\t\t\t\t\tresponse.setStatus(SC_OK);\t\n\t\t\t\t\t\t\tresponse.setHeader(\"Content-Length\", String.valueOf(packBlob.getSize()));\n\t\t\t\t\t\t\tresponse.setHeader(\"Docker-Content-Digest\", digestString);\n\t\t\t\t\t\t\treturn new Pair<>(packBlob.getProject().getId(), packBlob.getSha256Hash());\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthrow new NotFoundException(ErrorCode.BLOB_UNKNOWN);","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-plugin/server-plugin-pack-container/src/main/java/io/onedev/server/plugin/pack/container/ContainerServlet.java#L225-L261","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use POST .../blobs/uploads/ to initiate, PATCH to append chunks, and PUT ...?digest= to finalize.","Use GET .../blobs/<digest> (not the upload URL) to check whether a blob exists.","Use HEAD .../blobs/<digest> for existence checks; the upload session does not support it.","Fix the client's URL construction so upload-session and blob-fetch URLs are not mixed up."],"exampleFix":"// before\nPUT /v2/app/blobs/uploads/<uuid>            # wrong resource\n// after\nPUT /v2/app/blobs/uploads/<uuid>?digest=sha256:...   # finalize, or\nGET /v2/app/blobs/sha256:...                # fetch existing blob","handlingStrategy":"validation","validationCode":"const UPLOAD_METHODS = ['POST','PATCH','PUT','GET','DELETE'];\nif (!UPLOAD_METHODS.includes(method)) {\n  throw new Error(`Use POST/PATCH/PUT/GET/DELETE on blobs/uploads URLs, got ${method}`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Map operations to the right resources: POST=initiate, PATCH=chunk, PUT?digest=finalize.","Existence checks: HEAD/GET on /blobs/<digest>, never on the upload session URL.","Never PUT blobs directly to /blobs/<digest>; this registry requires the session flow.","Sanity-check generated URLs in custom clients against the OCI distribution spec."],"tags":["oci-registry","http-method","blob-upload","bad-request"],"backgroundTag":"unsupported-operation","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}