{"id":"a9d44cf9ae0c3057","repo":"jackc/pgx","slug":"short-write-to-large-object","errorCode":null,"errorMessage":"short write to large object","messagePattern":"short write to large object","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"large_objects.go","lineNumber":100,"sourceCode":"\t\t\tbreak\n\t\t} else if expected > maxLargeObjectMessageLength {\n\t\t\texpected = maxLargeObjectMessageLength\n\t\t}\n\n\t\tvar n int\n\t\terr := o.tx.QueryRow(o.ctx, \"select lowrite($1, $2)\", o.fd, p[nTotal:nTotal+expected]).Scan(&n)\n\t\tif err != nil {\n\t\t\treturn nTotal, err\n\t\t}\n\n\t\tif n < 0 {\n\t\t\treturn nTotal, errors.New(\"failed to write to large object\")\n\t\t}\n\n\t\tnTotal += n\n\n\t\tif n < expected {\n\t\t\treturn nTotal, errors.New(\"short write to large object\")\n\t\t} else if n > expected {\n\t\t\treturn nTotal, errors.New(\"invalid write to large object\")\n\t\t}\n\t}\n\n\treturn nTotal, nil\n}\n\n// Read reads up to len(p) bytes into p returning the number of bytes read.\nfunc (o *LargeObject) Read(p []byte) (int, error) {\n\tnTotal := 0\n\tfor {\n\t\texpected := len(p) - nTotal\n\t\tif expected == 0 {\n\t\t\tbreak\n\t\t} else if expected > maxLargeObjectMessageLength {\n\t\t\texpected = maxLargeObjectMessageLength\n\t\t}","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/jackc/pgx/blob/ec1a0befd22592cffffdeeb0a50311b506372f4c/large_objects.go#L82-L118","documentation":"Returned by LargeObject.Write when the server's lowrite reported a non-negative count strictly less than the bytes requested (large_objects.go:99-100). The server accepted fewer bytes than offered, which pgx treats as an error because the writer contract for io.Writer plus the chunking loop expects the full slice to be consumed. It indicates the large object is at capacity/exceeded its storage or the server truncated the write.","triggerScenarios":"Writing a chunk where lowrite returns n with 0 <= n < expected — the server wrote fewer bytes than the payload supplied in that lowrite call.","commonSituations":"Exceeding the large object size the server can hold in one operation; a server/extension quirk returning a partial count; running near the per-message or per-large-object limits.","solutions":["Retry the unwritten tail (the chunking loop already caps each lowrite at maxLargeObjectMessageLength; if you bypassed it, re-enable chunking).","Confirm the large object storage is healthy and the descriptor is still valid (re-open if the transaction ended).","If reproducible, capture the exact n vs. expected to file a pgx/PostgreSQL investigation — partial writes from lowrite are unusual.","Avoid writing more than maxLargeObjectMessageLength per call so the loop's chunking handles it."],"exampleFix":"// before — bypassing the chunk loop with one huge Write\n_, err := lo.Write(hugeSlice) // may surface 'short write'\n\n// after — let pgx chunk, or split yourself under maxLargeObjectMessageLength\nchunk := maxLargeObjectMessageLength\nfor off := 0; off < len(data); off += chunk {\n    end := off + chunk; if end > len(data) { end = len(data) }\n    if _, err := lo.Write(data[off:end]); err != nil { return err }\n}","handlingStrategy":"retry","validationCode":"// keep each Write under the protocol chunk cap so the loop can chunk cleanly\nconst chunk = 1024*1024*1024 - 1024 // maxLargeObjectMessageLength\nif len(p) > chunk {\n    // split before writing\n}","typeGuard":null,"tryCatchPattern":"// io.Writer contract; retry the tail once, then surface\nn, err := lo.Write(p[written:])\nif err != nil && err.Error() == \"short write to large object\" {\n    // unusual; investigate server state\n}\nwritten += n","preventionTips":["Let LargeObject.Write's internal chunking handle large payloads — do not bypass it.","Confirm the descriptor and transaction are still valid before large writes.","Capture n vs expected if it reproduces; partial lowrite results are atypical."],"tags":["large-objects","write","partial-write"],"analyzedSha":"ec1a0befd22592cffffdeeb0a50311b506372f4c","analyzedAt":"2026-08-04T22:52:11.263Z","schemaVersion":2}