{"record":{"id":"312ad46b22d26b20","repo":"k3s-io/k3s","slug":"only-wrote-d-bytes-to-s-expected-d","errorCode":null,"errorMessage":"only wrote %d bytes to %s; expected %d","messagePattern":"only wrote (.+?) bytes to (.+?); expected (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/untar/untar.go","lineNumber":91,"sourceCode":"\t\t\tif !madeDir[dir] {\n\t\t\t\tif err := os.MkdirAll(filepath.Dir(abs), 0755); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tmadeDir[dir] = true\n\t\t\t}\n\t\t\twf, err := os.OpenFile(abs, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode.Perm())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tn, err := io.Copy(wf, tr)\n\t\t\tif closeErr := wf.Close(); closeErr != nil && err == nil {\n\t\t\t\terr = closeErr\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error writing to %s: %v\", abs, err)\n\t\t\t}\n\t\t\tif n != f.Size {\n\t\t\t\treturn fmt.Errorf(\"only wrote %d bytes to %s; expected %d\", n, abs, f.Size)\n\t\t\t}\n\t\t\tmodTime := f.ModTime\n\t\t\tif modTime.After(t0) {\n\t\t\t\t// Clamp modtimes at system time. See\n\t\t\t\t// golang.org/issue/19062 when clock on\n\t\t\t\t// buildlet was behind the gitmirror server\n\t\t\t\t// doing the git-archive.\n\t\t\t\tmodTime = t0\n\t\t\t}\n\t\t\tif !modTime.IsZero() {\n\t\t\t\tif err := os.Chtimes(abs, modTime, modTime); err != nil && !loggedChtimesError {\n\t\t\t\t\t// benign error. Gerrit doesn't even set the\n\t\t\t\t\t// modtime in these, and we don't end up relying\n\t\t\t\t\t// on it anywhere (the gomote push command relies\n\t\t\t\t\t// on digests only), so this is a little pointless\n\t\t\t\t\t// for now.\n\t\t\t\t\tlogrus.Printf(\"error changing modtime: %v (further Chtimes errors suppressed)\", err)\n\t\t\t\t\tloggedChtimesError = true // once is enough","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/k3s-io/k3s/blob/6ba341e396edc16b8dcae978a7c5e3ac7ee5606e/pkg/untar/untar.go#L73-L109","documentation":"io.Copy into the extracted file returned no error but wrote fewer bytes than the tar header declared (f.Size). The tar stream is therefore shorter than its header claims - usually a truncated download, a zstd stream cut mid-entry, or a corrupt archive - and the extractor refuses to leave a silently incomplete file on disk.","triggerScenarios":"untar.Untar on a tarball truncated mid-file-entry (interrupted download, proxy cut-off, partial copy); a zstd stream that decodes short; a header whose Size is larger than the data actually stored.","commonSituations":"Image/airgap bundles partially downloaded over flaky networks; artifacts truncated by CI artifact size caps or storage limits; producer wrote the archive on a full disk or did not close/flush the tar and zstd writers before shipping.","solutions":["Verify integrity at the source: compare sha256sum with the producer, or run zstd -t file.tar.zst","Re-download or regenerate the tarball and retry the extraction","If you build the archive yourself, ensure tar.Close() and the zstd writer are flushed/closed before shipping","Check producer-side disk space if the archive was created on a nearly full host"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"func VerifyBundle(path, wantSHA256 string) error {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\th := sha256.New()\n\tif _, err := io.Copy(h, f); err != nil {\n\t\treturn err\n\t}\n\tif got := hex.EncodeToString(h.Sum(nil)); got != wantSHA256 {\n\t\treturn fmt.Errorf(\"checksum mismatch: got %s want %s\", got, wantSHA256)\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if err := untar.Untar(r, dir); err != nil {\n\tif strings.Contains(err.Error(), \"only wrote\") && strings.Contains(err.Error(), \"expected\") {\n\t\t// truncated/corrupt archive: delete the partial dir and re-download\n\t\tos.RemoveAll(dir)\n\t}\n\treturn err\n}","preventionTips":["Always verify sha256 of downloaded tarballs before extraction","Use zstd -t (or gzip -t) to validate compressed streams after download","Download to a temp file then extract; never stream-extract straight from a network connection","Ensure producers close tar and zstd writers before publishing archives"],"tags":["go","tar","corruption","download","io"],"backgroundTag":null,"analyzedSha":"6ba341e396edc16b8dcae978a7c5e3ac7ee5606e","analyzedAt":"2026-08-15T16:27:54.286Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}