{"record":{"id":"3e1905f60b4fcf7d","repo":"theonedev/onedev","slug":"denied","errorCode":"DENIED","errorMessage":"Manifest exceeds maximum size: ${MAX_MANIFEST_SIZE}","messagePattern":"Manifest exceeds maximum size: (.+?)","errorType":"http","errorClass":"ClientException","httpStatus":406,"severity":"error","filePath":"server-plugin/server-plugin-pack-container/src/main/java/io/onedev/server/plugin/pack/container/ContainerServlet.java","lineNumber":284,"sourceCode":"\t\t\t\t\t\t\t\tresponse.getOutputStream());\n\t\t\t\t\t}\n\t\t\t\t} else if (method.equals(\"DELETE\")) {\n\t\t\t\t\tthrow new ClientException(SC_METHOD_NOT_ALLOWED, ErrorCode.UNSUPPORTED);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new BadRequestException(\"Invalid http method for blob pull: \" + method);\n\t\t\t\t}\n\t\t\t} else if ((matcher = compile(\"(.+)/([^/]+)/manifests/([^/]+)\").matcher(pathInfo)).matches()) {\n\t\t\t\tvar projectPath = matcher.group(1);\n\t\t\t\tvar repository = matcher.group(2);\n\t\t\t\tvar reference = matcher.group(3);\n\t\t\t\tswitch (method) {\n\t\t\t\t\tcase \"PUT\":\n\t\t\t\t\t\tvar projectId = sessionService.call(() -> checkProject(projectPath, true).getId());\n\t\t\t\t\t\tvar baos = new ByteArrayOutputStream();\n\t\t\t\t\t\ttry (var is = request.getInputStream()) {\n\t\t\t\t\t\t\tvar copied = copyWithMaxSize(is, baos, MAX_MANIFEST_SIZE);\n\t\t\t\t\t\t\tif (copied == -1)\n\t\t\t\t\t\t\t\tthrow new ClientException(SC_NOT_ACCEPTABLE, ErrorCode.DENIED, \"Manifest exceeds maximum size: \" + MAX_MANIFEST_SIZE);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar bytes = baos.toByteArray();\n\t\t\t\t\t\tString hash;\n\t\t\t\t\t\tif (isTag(reference)) {\n\t\t\t\t\t\t\tvar packBlobId = packBlobService.uploadBlob(projectId, bytes, null);\n\t\t\t\t\t\t\t// Do not use lamda here as it may cause compilation error on terminal\n\t\t\t\t\t\t\thash = LockUtils.call(getLockName(projectId, repository), new Callable<String>() {\n\t\t\t\t\t\t\t\t@Override\n\t\t\t\t\t\t\t\tpublic String call() {\n\t\t\t\t\t\t\t\t\treturn sessionService.call(new Callable<>() {\n\n\t\t\t\t\t\t\t\t\t\tprivate PackBlob loadPackBlob(Map<String, PackBlob> packBlobs, String hash, long size) {\n\t\t\t\t\t\t\t\t\t\t\tvar packBlob = packBlobs.get(hash);\n\t\t\t\t\t\t\t\t\t\t\tif (packBlob == null) {\n\t\t\t\t\t\t\t\t\t\t\t\tpackBlob = packBlobService.findBySha256Hash(projectId, hash);\n\t\t\t\t\t\t\t\t\t\t\t\tif (packBlob != null) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tif (packBlob.getSize() == size)","sourceCodeStart":266,"sourceCodeEnd":302,"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#L266-L302","documentation":"Manifest PUT bodies are capped at MAX_MANIFEST_SIZE bytes; copyWithMaxSize returns -1 when the input exceeds that limit and the registry rejects the manifest with 406 and code DENIED. This protects the server from oversized/hostile payloads, since manifests are small JSON documents by spec.","triggerScenarios":"PUT /v2/<name>/manifests/<reference> with a body larger than MAX_MANIFEST_SIZE — typically an image index/manifest list referencing a huge number of descriptors, an accidentally POSTed layer blob to the manifests endpoint, or a non-manifest payload sent as the body.","commonSituations":"Multi-arch index manifests with hundreds of platforms/atannotations pushing past the cap; CI jobs uploading the wrong file (layer tarball instead of manifest JSON) to the manifest endpoint; clients that don't enforce OCI manifest size limits when constructing index manifests.","solutions":["Verify the body sent to /manifests/ is actually the JSON manifest/index, not a layer or config blob.","Trim the index manifest: remove unnecessary descriptors, annotations, or platforms to fit under MAX_MANIFEST_SIZE.","Upload large payloads via the blob endpoints; manifests must stay small by spec.","Check the client (buildkit/kaniko/buildah version) for known bugs generating bloated manifests; upgrade."],"exampleFix":"// before\ncurl -X PUT --data-binary @layer.tgz \"$reg/v2/app/manifests/1.0\"  # wrong file\n// after\ncurl -X PUT -H \"Content-Type: application/vnd.oci.image.manifest.v1+json\" \\\n     --data-binary @manifest.json \"$reg/v2/app/manifests/1.0\"","handlingStrategy":"validation","validationCode":"const fs = require('fs');\nconst MAX_MANIFEST_SIZE = 4 * 1024 * 1024; // match registry constant\nconst size = fs.statSync(manifestPath).size;\nif (size > MAX_MANIFEST_SIZE) throw new Error(`manifest ${size} bytes exceeds registry limit ${MAX_MANIFEST_SIZE}`);\nif (!manifestPath.endsWith('.json')) throw new Error('manifests endpoint expects JSON, not a blob');","typeGuard":null,"tryCatchPattern":"catch (err) {\n  if (err.status === 406 && err.code === 'DENIED' && /exceeds maximum size/.test(err.message)) {\n    // shrink index manifest or fix payload; do not retry as-is\n    throw new Error('Manifest too large: trim descriptors or check you are not uploading a blob');\n  }\n  throw err;\n}","preventionTips":["Confirm the file sent to /manifests/ is the manifest JSON, not a layer/config.","Keep index manifests lean (fewer descriptors/annotations).","Check manifest size in CI before PUT.","Upgrade builder tooling known to emit bloated manifests."],"tags":["oci-registry","manifest","payload-too-large","http-406"],"backgroundTag":"payload-too-large","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"}