{"record":{"id":"6a78ce9a78f9892a","repo":"hashicorp/terraform","slug":"file-exceeds-maximum-part-count","errorCode":null,"errorMessage":"file exceeds maximum part count","messagePattern":"file exceeds maximum part count","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/oci/multipart_upload.go","lineNumber":198,"sourceCode":"\t\t}\n\t\tsourceBlocks[i] = objectStorageSourceBlock{\n\t\t\tsection:     io.NewSectionReader(bytes.NewReader(m.Data), start, end-start),\n\t\t\tblockNumber: common.Int(i + 1),\n\t\t}\n\t}\n\treturn sourceBlocks, nil\n}\n\n/*\nSplitSizeToOffsetsAndLimits splits a file size into chunks based on DefaultFilePartSize.\nReturns the byte offsets and byte limits for each chunk.\nReturns an error if the size exceeds MaxCount parts.\n*/\nfunc SplitSizeToOffsetsAndLimits(size int64) ([]int64, int64, error) {\n\tpartSize := DefaultFilePartSize\n\ttotalParts := (size + partSize - 1) / partSize\n\tif totalParts > MaxCount {\n\t\treturn nil, 0, fmt.Errorf(\"file exceeds maximum part count\")\n\t}\n\toffsets := make([]int64, totalParts)\n\tfor i := range offsets {\n\t\toffsets[i] = int64(i) * partSize\n\t}\n\treturn offsets, partSize, nil\n}\n\nfunc (ctx *objectStorageMultiPartUploadContext) uploadPartsWorker() {\n\tfor block := range ctx.sourceBlocks {\n\t\tbuffer := make([]byte, block.section.Size())\n\t\t_, err := block.section.Read(buffer)\n\t\tif err != nil {\n\t\t\tctx.errChan <- fmt.Errorf(\"error reading source block %d: %w\", block.blockNumber, err)\n\t\t\treturn\n\t\t}\n\t\ttmpLength := int64(len(buffer))\n\t\tsum := md5.Sum(buffer)","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/oci/multipart_upload.go#L180-L216","documentation":"Thrown by SplitSizeToOffsetsAndLimits() when the computed number of parts exceeds MaxCount (10000). Each part is DefaultFilePartSize (128MB), so this triggers when the input data exceeds approximately 1.28 terabytes. It is a hard guard preventing OCI multipart uploads beyond the platform's part-count limit.","triggerScenarios":"Directly computed: totalParts = (size + 128MB - 1) / 128MB. If totalParts > 10000, the error fires. Called from objectMultiPartSplit() which is invoked from multiPartUploadImpl() during state Put operations exceeding 128MB.","commonSituations":"Never seen with legitimate Terraform/OpenTofu state files. Can surface in unit tests that lower DefaultFilePartSize (e.g. to 100 bytes in backend_test.go) and then pass data that produces more than 10000 100-byte chunks (i.e. >1MB of test data at that setting).","solutions":["Check whether DefaultFilePartSize was mutated by a test — if so, reset it or reduce test data size.","Verify the state file is not corrupted or bloated with unexpected content.","If this is a test, use data smaller than MaxCount * (test DefaultFilePartSize) — e.g. with 100-byte parts, keep data under 1MB.","In production, if state is genuinely enormous, restructure into smaller workspace-specific states."],"exampleFix":"// In tests, keep data within bounds of mutated part size:\n// At DefaultFilePartSize=100, MaxCount=10000 -> max safe size = 1,000,000 bytes\n// Use test data well under that limit\ntestData := make([]byte, 999900) // safe under 10000 parts at 100 bytes each","handlingStrategy":"validation","validationCode":"// Validate data size before calling SplitSizeToOffsetsAndLimits\nfunc canSplitToValidParts(size int64, partSize, maxCount int64) bool {\n    if partSize <= 0 {\n        return false\n    }\n    totalParts := (size + partSize - 1) / partSize\n    return totalParts <= maxCount\n}\n\n// Usage before multipart upload:\nif !canSplitToValidParts(dataSize, DefaultFilePartSize, MaxCount) {\n    return fmt.Errorf(\"cannot upload: size %d exceeds %d parts at %d bytes each\", dataSize, MaxCount, DefaultFilePartSize)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pre-check the size-to-parts ratio before attempting multipart split.","In tests, keep fixture data well below MaxCount * (test part size).","Monitor state file size growth as part of CI/CD pipeline."],"tags":["oci","multipart-upload","state-file","validation"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}