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

  1. Route cross-host operations through wshfs.Move, which handles them via copyInternal + delete.
  2. If you control the URIs, ensure source and destination share the same connection host so the same-host rename path applies.
  3. 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

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


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