{"record":{"id":"6ccacbf989d78a76","repo":"theonedev/onedev","slug":"file-length-incorrect","errorCode":null,"errorMessage":"File length incorrect: ","messagePattern":"File length incorrect: ","errorType":"http","errorClass":"ClientException","httpStatus":400,"severity":"error","filePath":"server-plugin/server-plugin-pack-npm/src/main/java/io/onedev/server/plugin/pack/npm/NpmPackHandler.java","lineNumber":371,"sourceCode":"\n\t\t\t\t\t\tvar distTags = new HashMap<String, String>();\n\t\t\t\t\t\tvar distTagsNode = packageMetadata.get(\"dist-tags\");\n\t\t\t\t\t\tif (distTagsNode != null) {\n\t\t\t\t\t\t\tfor (var it = distTagsNode.fields(); it.hasNext(); ) {\n\t\t\t\t\t\t\t\tvar field = it.next();\n\t\t\t\t\t\t\t\tdistTags.put(field.getKey(), field.getValue().asText());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar attachments = new HashMap<String, byte[]>();\n\t\t\t\t\t\tvar attachmentsNode = packageMetadata.get(\"_attachments\");\n\t\t\t\t\t\tif (attachmentsNode != null) {\n\t\t\t\t\t\t\tfor (var it = attachmentsNode.fields(); it.hasNext(); ) {\n\t\t\t\t\t\t\t\tvar field = it.next();\n\t\t\t\t\t\t\t\tvar fileName = field.getKey();\n\t\t\t\t\t\t\t\tvar fileContent = Base64.decodeBase64(field.getValue().get(\"data\").asText());\n\t\t\t\t\t\t\t\tif (fileContent.length != field.getValue().get(\"length\").asInt()) {\n\t\t\t\t\t\t\t\t\tthrow new ClientException(SC_BAD_REQUEST, \"File length incorrect: \" + fileName);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tattachments.put(fileName, fileContent);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar versionsNode = packageMetadata.get(\"versions\");\n\n\t\t\t\t\t\tpackageMetadata.remove(\"dist-tags\");\n\t\t\t\t\t\tpackageMetadata.remove(\"versions\");\n\t\t\t\t\t\tpackageMetadata.remove(\"_attachments\");\n\t\t\t\t\t\tpackageMetadata.remove(\"access\");\n\n\t\t\t\t\t\tbyte[] packageMetadataBytes = writeJson(packageMetadata);\n\n\t\t\t\t\t\tif (versionsNode != null) {\n\t\t\t\t\t\t\tfor (var it = versionsNode.fields(); it.hasNext(); ) {\n\t\t\t\t\t\t\t\tvar field = it.next();\n\t\t\t\t\t\t\t\tvar version = field.getKey();","sourceCodeStart":353,"sourceCodeEnd":389,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-plugin/server-plugin-pack-npm/src/main/java/io/onedev/server/plugin/pack/npm/NpmPackHandler.java#L353-L389","documentation":"npm publish metadata contains an _attachments object where each attachment declares its content (base64 'data') and a 'length' field. The handler decodes the base64 data and compares the decoded byte length to the declared length; a mismatch throws ClientException HTTP 400 'File length incorrect: <fileName>'.","triggerScenarios":"Publishing with metadata where an attachment's 'length' field does not equal the byte length of its base64-decoded 'data' — corrupted metadata generation, manual construction of publish payloads, or truncation in transit/transform.","commonSituations":"Custom publish scripts hand-building the npm publish document; proxies modifying/truncating base64 payloads; libraries generating attachments with wrong length fields; encoding issues (e.g. re-encoding data as base64 twice).","solutions":["Regenerate the publish payload with a standard npm client instead of hand-crafting JSON","Ensure the 'length' field equals the byte length of the decoded 'data' for every attachment","Check any intermediate proxy/pipeline for payload truncation or transformation","Verify the file wasn't modified after length was computed (re-run npm publish)"],"exampleFix":"// before\n\"length\": 1024,\n\"data\": \"<base64 of 2048-byte tarball>\"\n// after\n\"length\": 2048,\n\"data\": \"<base64 of 2048-byte tarball>\"","handlingStrategy":"validation","validationCode":"for (const [name, att] of Object.entries(meta._attachments)) {\n  const bytes = Buffer.from(att.data, 'base64');\n  if (bytes.length !== att.length) throw new Error(`Attachment ${name} length mismatch: ${bytes.length} != ${att.length}`);\n}","typeGuard":"function hasConsistentAttachment(att) {\n  return typeof att?.data === 'string' && typeof att?.length === 'number'\n    && Buffer.from(att.data, 'base64').length === att.length;\n}","tryCatchPattern":"try { await publish() } catch (e) { if (e.response?.status === 400 && /File length incorrect/i.test(e.message ?? '')) { console.error('Attachment length field does not match decoded data'); } else throw e }","preventionTips":["Let standard npm clients build publish payloads","Never transform or truncate base64 bodies in transit","Validate _attachments locally before publishing in custom scripts"],"tags":["http-400","npm","validation","publish"],"backgroundTag":"schema-validation-failed","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}