{"record":{"id":"0ffe6273a2631588","repo":"wavetermdev/waveterm","slug":"stream-file-protocol-error-no-file-info","errorCode":null,"errorMessage":"stream file protocol error, no file info","messagePattern":"stream file protocol error, no file info","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/remote/fileshare/fsutil/fsutil.go","lineNumber":144,"sourceCode":"\tvar entries []*wshrpc.FileInfo\n\terr := ReadFileStream(ctx, readCh, func(finfo wshrpc.FileInfo) {\n\t\tfileData = &wshrpc.FileData{\n\t\t\tInfo: &finfo,\n\t\t}\n\t}, func(fileEntries []*wshrpc.FileInfo) error {\n\t\tentries = append(entries, fileEntries...)\n\t\treturn nil\n\t}, func(data io.Reader) error {\n\t\tif _, err := io.Copy(&dataBuf, data); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif fileData == nil {\n\t\treturn nil, fmt.Errorf(\"stream file protocol error, no file info\")\n\t}\n\tif !fileData.Info.IsDir {\n\t\tfileData.Data64 = base64.StdEncoding.EncodeToString(dataBuf.Bytes())\n\t} else {\n\t\tfileData.Entries = entries\n\t}\n\treturn fileData, nil\n}\n","sourceCodeStart":126,"sourceCodeEnd":153,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/remote/fileshare/fsutil/fsutil.go#L126-L153","documentation":"ReadStreamToFileData wraps ReadFileStream and collects the file data/entries via callbacks. After a successful stream, fileData must have been set by the first-packet Info callback; if it is still nil the protocol produced no file info, so this error is returned.","triggerScenarios":"Calling ReadStreamToFileData against a remote whose stream ends (readCh closed) without ever sending the first Info packet — empty/aborted stream from an incompatible or buggy responder.","commonSituations":"Remote aborted the stream immediately (permission change mid-read); wsh version mismatch causing the responder to close before sending info; zero-length stream due to remote filesystem error swallowed upstream.","solutions":["Retry the read after confirming the remote path exists and is accessible","Upgrade wsh on both ends so the stream always begins with the Info packet","Check remote permissions on the target path","Inspect remote logs for responder-side stream aborts"],"exampleFix":"// before\ndata, err := fsutil.ReadStreamToFileData(ctx, ctl, path) // nil fileData\n// after\nif fi, statErr := remoteStat(ctx, ctl, path); statErr != nil || fi == nil {\n    return nil, fmt.Errorf(\"remote path %q unavailable\", path)\n}\ndata, err := fsutil.ReadStreamToFileData(ctx, ctl, path)","handlingStrategy":"validation","validationCode":"if fi, err := remoteStat(ctx, ctl, path); err != nil || fi == nil {\n    return fmt.Errorf(\"remote path %q is not readable\", path)\n}","typeGuard":"func streamHasInfo(data *fileshare.StreamData) bool { return data != nil && data.Info != nil }","tryCatchPattern":"data, err := fsutil.ReadStreamToFileData(ctx, ctl, path)\nif err != nil && strings.Contains(err.Error(), \"no file info\") {\n    return fmt.Errorf(\"remote returned an empty stream for %q — check permissions/version\", path)\n}","preventionTips":["Verify remote readability before streaming","Keep fileshare protocol versions in sync","Handle empty/aborted streams explicitly instead of assuming data arrives"],"tags":["go","protocol","stream"],"backgroundTag":"stream-protocol-violation","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}