{"record":{"id":"4ca17d68b8035cbc","repo":"wavetermdev/waveterm","slug":"writerchan-write-error-v","errorCode":null,"errorMessage":"WriterChan: write error: %v","messagePattern":"WriterChan: write error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/util/iochan/iochan.go","lineNumber":96,"sourceCode":"\t\t\t\t}\n\t\t\t\tif resp.Error != nil {\n\t\t\t\t\tcancel(resp.Error)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif _, err := sha256Hash.Write(resp.Response.Data); err != nil {\n\t\t\t\t\tcancel(fmt.Errorf(\"WriterChan: error writing to sha256 hash: %v\", err))\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// The checksum is sent as the last packet\n\t\t\t\tif resp.Response.Checksum != nil {\n\t\t\t\t\tlocalChecksum := sha256Hash.Sum(nil)\n\t\t\t\t\tif !bytes.Equal(localChecksum, resp.Response.Checksum) {\n\t\t\t\t\t\tcancel(fmt.Errorf(\"WriterChan: checksum mismatch\"))\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif _, err := w.Write(resp.Response.Data); err != nil {\n\t\t\t\t\tcancel(fmt.Errorf(\"WriterChan: write error: %v\", err))\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n}\n","sourceCodeStart":78,"sourceCodeEnd":103,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/util/iochan/iochan.go#L78-L103","documentation":"WriterChan receives data packets from a channel and writes them to the destination io.Writer. When the underlying Write call returns an error (disk full, closed pipe, broken connection, permission denied), the streaming context is cancelled with 'WriterChan: write error: <underlying error>'. The wrapped error message contains the real cause.","triggerScenarios":"Calling WriterChan with an io.Writer whose Write fails: writing to a closed file/socket, disk full, permission denied on the output file, writing to an io.Writer already closed by another goroutine, or a network writer whose peer disconnected.","commonSituations":"Downloading a remote file into a local file that was deleted or hit its quota; writing to an os.Pipe whose reader closed; output stream to a terminal/ssh session that was closed mid-transfer.","solutions":["Inspect the wrapped error text after this message for the root cause (e.g. 'no space left on device', 'file already closed', 'broken pipe').","Free disk space or fix permissions on the destination before retrying.","Keep the destination io.Writer open until the context is done; close it only after WriterChan finishes (callback).","If the destination is a network stream, reconnect and restart the transfer.","Handle SIGPIPE/broken-pipe cases by cancelling the sender early rather than continuing to read."],"exampleFix":"// before: closing the file while WriterChan may still write\nf, _ := os.Create(dest)\niochan.WriterChan(ctx, f, ch, nil, cancel)\nf.Close()\n// after: close only after the writer goroutine completes\ndone := make(chan struct{})\niochan.WriterChan(ctx, f, ch, func() { close(done) }, cancel)\n<-done\nf.Close()","handlingStrategy":"try-catch","validationCode":"f, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY, 0644)\nif err != nil { return err }\nif stat, err := f.Stat(); err == nil {\n    if avail, _ := diskFree(destDir); avail < expectedSize { return errors.New(\"insufficient disk space\") }\n    _ = stat\n}","typeGuard":"func isWriteError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"WriterChan: write error:\")\n}","tryCatchPattern":"if err := context.Cause(ctx); err != nil {\n    if isWriteError(err) {\n        log.Printf(\"destination write failed: %v\", err)\n        // inspect wrapped cause: ENOSPC, EPIPE, permission denied, etc.\n        return fmt.Errorf(\"cannot write destination: %w\", err)\n    }\n    return err\n}","preventionTips":["Keep the destination io.Writer open until WriterChan's callback fires; close it afterwards.","Check disk space and write permissions on the destination before large transfers.","Avoid sharing one io.Writer across concurrent WriterChan goroutines.","Detect destination closure (pipe/ssh disconnect) and cancel the sender promptly."],"tags":["io","write-error","streaming","go"],"backgroundTag":"stream-write-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}