{"record":{"id":"7afe72e0e7d1198c","repo":"wavetermdev/waveterm","slug":"context-cancelled-v","errorCode":null,"errorMessage":"context cancelled: %v","messagePattern":"context cancelled: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/remote/fileshare/fsutil/fsutil.go","lineNumber":77,"sourceCode":"\t}\n\treturn fspath.Join(newParts...), nil\n}\n\nfunc ReadFileStream(ctx context.Context, readCh <-chan wshrpc.RespOrErrorUnion[wshrpc.FileData], fileInfoCallback func(finfo wshrpc.FileInfo), dirCallback func(entries []*wshrpc.FileInfo) error, fileCallback func(data io.Reader) error) error {\n\tvar fileData *wshrpc.FileData\n\tfirstPk := true\n\tisDir := false\n\tdrain := true\n\tdefer func() {\n\t\tif drain {\n\t\t\tutilfn.DrainChannelSafe(readCh, \"ReadFileStream\")\n\t\t}\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn fmt.Errorf(\"context cancelled: %v\", context.Cause(ctx))\n\t\tcase respUnion, ok := <-readCh:\n\t\t\tif !ok {\n\t\t\t\tdrain = false\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif respUnion.Error != nil {\n\t\t\t\treturn respUnion.Error\n\t\t\t}\n\t\t\tresp := respUnion.Response\n\t\t\tif firstPk {\n\t\t\t\tfirstPk = false\n\t\t\t\t// first packet has the fileinfo\n\t\t\t\tif resp.Info == nil {\n\t\t\t\t\treturn fmt.Errorf(\"stream file protocol error, first pk fileinfo is empty\")\n\t\t\t\t}\n\t\t\t\tfileData = &resp\n\t\t\t\tif fileData.Info.IsDir {\n\t\t\t\t\tisDir = true","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/remote/fileshare/fsutil/fsutil.go#L59-L95","documentation":"ReadFileStream streams file contents from a remote host over the fileshare protocol. It selects on the caller's context; when ctx is done (cancelled or deadline exceeded) it aborts the stream and returns this error carrying context.Cause.","triggerScenarios":"ReadStreamToFileData (or a direct ReadFileStream call) with a context that is cancelled or whose deadline expires while waiting on readCh from the remote stream.","commonSituations":"Slow or hung remote host exceeding the caller's timeout; user cancels a large directory-listing/download; upstream request cancelled (client disconnect); network stall causing deadline to fire.","solutions":["Increase the context timeout for large transfers","Retry with a fresh context — the stream is aborted, not resumable","Check remote host responsiveness/network stability","Propagate parent cancellation intentionally if this is expected shutdown"],"exampleFix":"// before\nctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // too short\ndata, err := fsutil.ReadStreamToFileData(ctx, ctl, \"/big/file\")\n// after\nctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)\ndata, err := fsutil.ReadStreamToFileData(ctx, ctl, \"/big/file\")","handlingStrategy":"retry","validationCode":"if ctx.Err() != nil {\n    return fmt.Errorf(\"context already done before stream: %w\", ctx.Err())\n}","typeGuard":null,"tryCatchPattern":"data, err := fsutil.ReadStreamToFileData(ctx, ctl, path)\nif err != nil && errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) || strings.Contains(err.Error(), \"context cancelled\") {\n    ctx2, cancel := context.WithTimeout(context.Background(), longerTimeout)\n    defer cancel()\n    data, err = fsutil.ReadStreamToFileData(ctx2, ctl, path)\n}","preventionTips":["Size timeouts to the transfer volume (large dirs need more)","Only cancel contexts intentionally; propagate cancel to UI","Monitor remote latency to set realistic deadlines"],"tags":["go","context","timeout"],"backgroundTag":"context-cancelled","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}