hashicorp/terraform · error

file exceeds maximum part count

Error message

file exceeds maximum part count

What it means

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.

Solutions

  1. Check whether DefaultFilePartSize was mutated by a test — if so, reset it or reduce test data size.
  2. Verify the state file is not corrupted or bloated with unexpected content.
  3. If this is a test, use data smaller than MaxCount * (test DefaultFilePartSize) — e.g. with 100-byte parts, keep data under 1MB.
  4. In production, if state is genuinely enormous, restructure into smaller workspace-specific states.

Example fix

// In tests, keep data within bounds of mutated part size:
// At DefaultFilePartSize=100, MaxCount=10000 -> max safe size = 1,000,000 bytes
// Use test data well under that limit
testData := make([]byte, 999900) // safe under 10000 parts at 100 bytes each
Defensive patterns

Strategy: validation

Validate before calling

// Validate data size before calling SplitSizeToOffsetsAndLimits
func canSplitToValidParts(size int64, partSize, maxCount int64) bool {
    if partSize <= 0 {
        return false
    }
    totalParts := (size + partSize - 1) / partSize
    return totalParts <= maxCount
}

// Usage before multipart upload:
if !canSplitToValidParts(dataSize, DefaultFilePartSize, MaxCount) {
    return fmt.Errorf("cannot upload: size %d exceeds %d parts at %d bytes each", dataSize, MaxCount, DefaultFilePartSize)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/6a78ce9a78f9892a. Report an issue: GitHub.

Appendix: source

Thrown at internal/backend/remote-state/oci/multipart_upload.go:198

		}
		sourceBlocks[i] = objectStorageSourceBlock{
			section:     io.NewSectionReader(bytes.NewReader(m.Data), start, end-start),
			blockNumber: common.Int(i + 1),
		}
	}
	return sourceBlocks, nil
}

/*
SplitSizeToOffsetsAndLimits splits a file size into chunks based on DefaultFilePartSize.
Returns the byte offsets and byte limits for each chunk.
Returns an error if the size exceeds MaxCount parts.
*/
func SplitSizeToOffsetsAndLimits(size int64) ([]int64, int64, error) {
	partSize := DefaultFilePartSize
	totalParts := (size + partSize - 1) / partSize
	if totalParts > MaxCount {
		return nil, 0, fmt.Errorf("file exceeds maximum part count")
	}
	offsets := make([]int64, totalParts)
	for i := range offsets {
		offsets[i] = int64(i) * partSize
	}
	return offsets, partSize, nil
}

func (ctx *objectStorageMultiPartUploadContext) uploadPartsWorker() {
	for block := range ctx.sourceBlocks {
		buffer := make([]byte, block.section.Size())
		_, err := block.section.Read(buffer)
		if err != nil {
			ctx.errChan <- fmt.Errorf("error reading source block %d: %w", block.blockNumber, err)
			return
		}
		tmpLength := int64(len(buffer))
		sum := md5.Sum(buffer)

View on GitHub (pinned to d32a084675)