wavetermdev/waveterm · error

stream file protocol error, directory entry has data

Error message

stream file protocol error, directory entry has data

What it means

When streaming a directory, each packet should contain directory entries and no payload data. ReadFileStream rejects a directory packet that carries Data64, since directory listings must not include file content — a protocol violation by the remote responder.

Source

Thrown at pkg/remote/fileshare/fsutil/fsutil.go:105

			if firstPk {
				firstPk = false
				// first packet has the fileinfo
				if resp.Info == nil {
					return fmt.Errorf("stream file protocol error, first pk fileinfo is empty")
				}
				fileData = &resp
				if fileData.Info.IsDir {
					isDir = true
				}
				fileInfoCallback(*fileData.Info)
				continue
			}
			if isDir {
				if len(resp.Entries) == 0 {
					continue
				}
				if resp.Data64 != "" {
					return fmt.Errorf("stream file protocol error, directory entry has data")
				}
				if err := dirCallback(resp.Entries); err != nil {
					return err
				}
			} else {
				if resp.Data64 == "" {
					continue
				}
				decoder := base64.NewDecoder(base64.StdEncoding, bytes.NewReader([]byte(resp.Data64)))
				if err := fileCallback(decoder); err != nil {
					return err
				}
			}
		}
	}
}

func ReadStreamToFileData(ctx context.Context, readCh <-chan wshrpc.RespOrErrorUnion[wshrpc.FileData]) (*wshrpc.FileData, error) {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Ensure client and remote wsh versions match and are current
  2. Restart the file stream — desynced streams cannot recover mid-stream
  3. List the directory entries individually instead of streaming as one call
  4. Report/inspect the remote responder implementation if reproducible

Example fix

// before
data, err := fsutil.ReadStreamToFileData(ctx, ctl, dirPath) // dir packet has data
// after
if isRemoteDir(ctx, ctl, dirPath) {
    err = streamDirEntriesOnly(ctx, ctl, dirPath) // entries-only streaming path
} else {
    data, err = fsutil.ReadStreamToFileData(ctx, ctl, dirPath)
}
Defensive patterns

Strategy: type-guard

Validate before calling

fi, _ := remoteStat(ctx, ctl, path)
if fi != nil && fi.IsDir {
    // use the directory streaming path, not the file-data path
}

Type guard

func isDirPacketOk(resp fileshare.StreamResponse) bool {
    return resp.Info != nil && !resp.Info.IsDir || (resp.Info.IsDir && resp.Data64 == "")
}

Try / catch

_, err := fsutil.ReadStreamToFileData(ctx, ctl, dir)
if err != nil && strings.Contains(err.Error(), "directory entry has data") {
    return fmt.Errorf("remote protocol mismatch — upgrade wsh on both ends")
}

Prevention

When it happens

Trigger: ReadStreamToFileData on a directory where the remote sends entries together with non-empty Data64 — e.g. a mismatched fileshare implementation or corrupted stream framing.

Common situations: Version mismatch between client and remote wsh protocol; remote bug sending file-style packets for directories; stream desync after a prior packet error.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/1e98e9f6691d9d5f. Report an issue: GitHub.