{"record":{"id":"b7d5a47563d5f510","repo":"containerd/containerd","slug":"failed-to-send-write-w","errorCode":null,"errorMessage":"failed to send write: %w","messagePattern":"failed to send write: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/content/proxy/content_writer.go","lineNumber":91,"sourceCode":"\t}, nil\n}\n\nfunc (rw *remoteWriter) Digest() digest.Digest {\n\treturn rw.digest\n}\n\nfunc (rw *remoteWriter) Write(p []byte) (n int, err error) {\n\tconst maxBufferSize = defaults.DefaultMaxSendMsgSize >> 1\n\tfor data := range slices.Chunk(p, maxBufferSize) {\n\t\toffset := rw.offset\n\n\t\tresp, err := rw.send(&contentapi.WriteContentRequest{\n\t\t\tAction: contentapi.WriteAction_WRITE,\n\t\t\tOffset: offset,\n\t\t\tData:   data,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn 0, fmt.Errorf(\"failed to send write: %w\", errgrpc.ToNative(err))\n\t\t}\n\n\t\twritten := int(resp.Offset - offset)\n\t\trw.offset += int64(written)\n\t\tif resp.Digest != \"\" {\n\t\t\trw.digest = digest.Digest(resp.Digest)\n\t\t}\n\t\tn += written\n\n\t\tif written < len(data) {\n\t\t\treturn n, io.ErrShortWrite\n\t\t}\n\t}\n\treturn n, nil\n}\n\nfunc (rw *remoteWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) (err error) {\n\tdefer func() {","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/containerd/containerd/blob/4246446a2bf7d03837b0244118d858799393bd80/core/content/proxy/content_writer.go#L73-L109","documentation":"remoteWriter.Write sends WriteAction_WRITE requests carrying data chunks through the containerd content proxy. If the RPC fails, the native (errgrpc.ToNative) error is wrapped with 'failed to send write' and Write returns 0 bytes written.","triggerScenarios":"Calling Write on a proxied content writer when the underlying write RPC fails — connection reset by the daemon, context cancellation, socket buffer overflow with oversized data chunks, or remote ingest closed.","commonSituations":"Pushing large layers to a daemon that restarts mid-transfer; writing chunks larger than the ttrpc/gRPC message size limit; cancelled context during blob upload; network interruption between proxy and remote worker.","solutions":["Check the wrapped gRPC code: ResourceExhausted means reduce chunk size (default write buffer) or raise the message size limit","Retry the transfer from the last known offset using Status(); the proxy writer supports resuming via the offset field","Ensure the context is not cancelled/timed out prematurely during large writes","Verify the containerd daemon and ttrpc socket stayed connected for the duration of the write"],"exampleFix":"// before: one huge chunk\nn, err := rw.Write(bigBuffer) // ResourceExhausted\n// after: bounded chunks\nconst chunk = 1 << 20\nfor len(bigBuffer) > 0 {\n    c := bigBuffer\n    if len(c) > chunk { c = c[:chunk] }\n    if _, err := rw.Write(c); err != nil { return err }\n    bigBuffer = bigBuffer[len(c):]\n}","handlingStrategy":"try-catch","validationCode":"// check remote offset before writing next chunk\nst, err := rw.Status()\nif err != nil { return err }\nif st.Offset != expectedOffset {\n    return fmt.Errorf(\"offset drift: remote %d != local %d\", st.Offset, expectedOffset)\n}","typeGuard":null,"tryCatchPattern":"n, err := rw.Write(chunk)\nif err != nil {\n    switch {\n    case errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded):\n        return err\n    case status.Code(err) == codes.ResourceExhausted:\n        return retryWithSmallerChunk(chunk[:len(chunk)/2])\n    default:\n        return resumeFromStatus(ctx) // re-sync via Status() and continue\n    }\n}","preventionTips":["Write in bounded chunks (e.g. 1MB) rather than whole blobs","Use resumable writes: check Status() and skip to the confirmed offset","Keep the context alive for the full transfer duration"],"tags":["grpc","ttrpc","content-writer","upload","rpc-error"],"backgroundTag":"rpc-write-failed","analyzedSha":"4246446a2bf7d03837b0244118d858799393bd80","analyzedAt":"2026-09-02T00:14:43.053Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}