{"record":{"id":"3d08554ba52be9bd","repo":"golang/go","slug":"error-size-of-s-changed-during-reading-from-d-3d0855","errorCode":null,"errorMessage":"error: size of %s changed during reading (from %d to >=%d bytes)","messagePattern":"error: size of (.+?) changed during reading \\(from (.+?) to >=(.+?) bytes\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/gofmt/gofmt.go","lineNumber":361,"sourceCode":"\t// read more than size bytes, then the file was modified concurrently.\n\t// (If that happens, we could, say, append to src to finish the read, or\n\t// proceed with a truncated buffer — but the fact that it changed at all\n\t// indicates a possible race with someone editing the file, so we prefer to\n\t// stop to avoid corrupting it.)\n\tsrc := make([]byte, size+1)\n\tn, err := io.ReadFull(in, src)\n\tswitch err {\n\tcase nil, io.EOF, io.ErrUnexpectedEOF:\n\t\t// io.ReadFull returns io.EOF (for an empty file) or io.ErrUnexpectedEOF\n\t\t// (for a non-empty file) if the file was changed unexpectedly. Continue\n\t\t// with comparing file sizes in those cases.\n\tdefault:\n\t\treturn nil, err\n\t}\n\tif n < size {\n\t\treturn nil, fmt.Errorf(\"error: size of %s changed during reading (from %d to %d bytes)\", filename, size, n)\n\t} else if n > size {\n\t\treturn nil, fmt.Errorf(\"error: size of %s changed during reading (from %d to >=%d bytes)\", filename, size, len(src))\n\t}\n\treturn src[:n], nil\n}\n\nfunc main() {\n\t// Arbitrarily limit in-flight work to 2MiB times the number of threads.\n\t//\n\t// The actual overhead for the parse tree and output will depend on the\n\t// specifics of the file, but this at least keeps the footprint of the process\n\t// roughly proportional to GOMAXPROCS.\n\tmaxWeight := (2 << 20) * int64(runtime.GOMAXPROCS(0))\n\ts := newSequencer(maxWeight, os.Stdout, os.Stderr)\n\n\t// call gofmtMain in a separate function\n\t// so that it can use defer and have them\n\t// run before the exit.\n\tgofmtMain(s)\n\tos.Exit(s.GetExitCode())","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/gofmt/gofmt.go#L343-L379","documentation":"Thrown by gofmt's reader when io.ReadFull fills the entire size+1 buffer (n>size), proving the file grew beyond the size previously returned by os.Stat. Because src is allocated as size+1, n>size means n==len(src)==size+1, so the true new length is unknown (hence the `>=` in the message). gofmt refuses to format a moving target.","triggerScenarios":"A concurrent process appends to or lengthens the file between Stat and ReadFull. The buffer was sized for the old length, ReadFull saturated it and still had bytes available, so the read is unreliable.","commonSituations":"Live log files being formatted by mistake, code generators appending during gofmt, an editor saving a larger buffer, or two gofmt/process instances racing on the same file.","solutions":["Re-run gofmt when the file is quiescent.","Exclude growing files (logs, generated output) from gomt's input set.","Serialize writers — run `go generate` then gofmt, not in parallel.","In watch mode, debounce or lock the file before formatting."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for i := 0; i < 3; i++ {\n    if err := runGofmt(file); err == nil { break }\n    if !strings.Contains(err.Error(), \"changed during reading\") { break }\n    time.Sleep(100 * time.Millisecond << i)\n}","preventionTips":["Serialize writers — finish `go generate` before gofmt.","Exclude ever-growing files (logs, generated output) from gofmt input.","Snapshot/copy the file to a temp path and format the copy if the source is hot."],"tags":["gofmt","race-condition","filesystem","concurrency"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}