wavetermdev/waveterm · error
move internal, src and dest hosts do not match
Error message
move internal, src and dest hosts do not match
What it means
moveInternal is wshfs's same-host fast path: it issues a single RemoteFileMoveCommand RPC to the destination host. If the source and destination hosts differ, it refuses with this sentinel message instead of doing a silent cross-host copy — cross-host moves must go through the copy+delete path in Move. This is a defensive invariant check; Move already routes cross-host cases to copyInternal, so reaching this error indicates a logic inconsistency or direct misuse.
Source
Thrown at pkg/remote/fileshare/wshfs/wshfs.go:282
return delete_(conn, data.Recursive)
}
func delete_(conn *connparse.Connection, recursive bool) error {
return wshclient.RemoteFileDeleteCommand(RpcClient, wshrpc.CommandDeleteFileData{Path: conn.Path, Recursive: recursive}, &wshrpc.RpcOpts{Route: wshutil.MakeConnectionRouteId(conn.Host)})
}
func Join(ctx context.Context, path string, parts ...string) (*wshrpc.FileInfo, error) {
log.Printf("Join: %v", path)
conn, err := parseConnection(ctx, path)
if err != nil {
return nil, err
}
return wshclient.RemoteFileJoinCommand(RpcClient, append([]string{conn.Path}, parts...), &wshrpc.RpcOpts{Route: wshutil.MakeConnectionRouteId(conn.Host)})
}
func moveInternal(srcConn, destConn *connparse.Connection, opts *wshrpc.FileCopyOpts) error {
if srcConn.Host != destConn.Host {
return fmt.Errorf("move internal, src and dest hosts do not match")
}
if opts == nil {
opts = &wshrpc.FileCopyOpts{}
}
timeout := opts.Timeout
if timeout == 0 {
timeout = DefaultTimeout.Milliseconds()
}
return wshclient.RemoteFileMoveCommand(RpcClient, wshrpc.CommandFileCopyData{SrcUri: srcConn.GetFullURI(), DestUri: destConn.GetFullURI(), Opts: opts}, &wshrpc.RpcOpts{Route: wshutil.MakeConnectionRouteId(destConn.Host), Timeout: timeout})
}
func copyInternal(srcConn, destConn *connparse.Connection, opts *wshrpc.FileCopyOpts) (bool, error) {
if opts == nil {
opts = &wshrpc.FileCopyOpts{}
}
timeout := opts.Timeout
if timeout == 0 {
timeout = DefaultTimeout.Milliseconds()View on GitHub (pinned to a4447c1563)
Solutions
- Route cross-host operations through wshfs.Move, which handles them via copyInternal + delete.
- If you control the URIs, ensure source and destination share the same connection host so the same-host rename path applies.
- If you see this from stock Move usage, report it as a bug — the guard should be unreachable.
Example fix
// before
// calling moveInternal directly with different hosts
moveInternal(srcConn, destConn, opts)
// after
Move(ctx, wshrpc.CommandFileCopyData{SrcUri: srcConn.GetFullURI(), DestUri: destConn.GetFullURI(), Opts: opts}) Defensive patterns
Strategy: validation
Validate before calling
src, _ := connparse.ParseConnection(ctx, srcUri)
dst, _ := connparse.ParseConnection(ctx, destUri)
if src.Host != dst.Host {
// use Move (copy+delete fallback), not the same-host move path
} Prevention
- Only use the same-host rename path when parsed hosts match.
- Route all user-driven moves through wshfs.Move.
- Treat this error as an internal invariant violation and file a bug if hit via public API.
When it happens
Trigger: moveInternal being invoked with srcConn.Host != destConn.Host — either called directly by internal code with mismatched parsed connections, or a race where host comparison in Move passed but connections differ. In normal use via Move it should be unreachable.
Common situations: Custom code calling moveInternal (or an older variant) directly without the host check; refactors that bypass Move's host-comparison branch.
Related errors
- file data size %d exceeds transfer limit of %d bytes
- error parsing destination connection: %w
- cannot copy %q to %q: %w
- beginning of file
- procinfo: process not found
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/97036524b31b81d5.
Report an issue: GitHub.