wavetermdev/waveterm · error
could not create symlink %s -> %s: %w
Error message
could not create symlink %s -> %s: %w
What it means
ConnServerInitCommand could not create the wsh socket symlink on the remote (or local) host, so the wsh server endpoint is not reachable at the expected path. os.Symlink failed and the target paths are included in the message.
Source
Thrown at pkg/wshrpc/wshremote/wshremote.go:124
func (impl *ServerImpl) ConnServerInitCommand(ctx context.Context, data wshrpc.CommandConnServerInitData) error {
if data.ClientId == "" {
return fmt.Errorf("clientid is required")
}
if impl.SockName == "" {
return fmt.Errorf("sockname not set in server impl")
}
symlinkPath, err := wavebase.ExpandHomeDir(wavebase.GetPersistentRemoteSockName(data.ClientId))
if err != nil {
return fmt.Errorf("cannot expand symlink path: %w", err)
}
symlinkDir := filepath.Dir(symlinkPath)
if err := os.MkdirAll(symlinkDir, 0700); err != nil {
return fmt.Errorf("could not create client directory %s: %w", symlinkDir, err)
}
os.Remove(symlinkPath)
if err := os.Symlink(impl.SockName, symlinkPath); err != nil {
return fmt.Errorf("could not create symlink %s -> %s: %w", symlinkPath, impl.SockName, err)
}
impl.Log("created symlink %s -> %s\n", symlinkPath, impl.SockName)
return nil
}
func (impl *ServerImpl) getWshPath() (string, error) {
if impl.IsLocal {
return filepath.Join(wavebase.GetWaveDataDir(), "bin", "wsh"), nil
}
wshPath, err := wavebase.ExpandHomeDir("~/.waveterm/bin/wsh")
if err != nil {
return "", fmt.Errorf("cannot expand wsh path: %w", err)
}
return wshPath, nil
}
func (impl *ServerImpl) BadgeWatchPidCommand(ctx context.Context, data wshrpc.CommandBadgeWatchPidData) error {
if data.Pid <= 0 {View on GitHub (pinned to a4447c1563)
Solutions
- Manually remove the stale symlink: rm ~/.waveterm/.../sockname then restart connection
- Check the target filesystem supports symlinks (not FAT/some network mounts)
- Verify symlinkDir permissions and that MkdirAll succeeded (0700)
- Check the wrapped cause (EEXIST/EPERM/ENOSYS) for the exact OS reason
Defensive patterns
Strategy: fallback
Validate before calling
if fi, err := os.Lstat(symlinkPath); err == nil {
if err := os.Remove(symlinkPath); err != nil {
return fmt.Errorf("cannot clear stale symlink: %w", err)
}
} Try / catch
if err := ConnServerInitCommand(ctx, data); err != nil {
if strings.Contains(err.Error(), "could not create symlink") {
// fall back: log and retry after removing stale link
os.Remove(symlinkPath)
return ConnServerInitCommand(ctx, data)
}
return err
} Prevention
- Always remove stale symlinks before creating (already done via os.Remove — check its error too)
- Avoid placing sockets/symlinks on non-symlink-capable filesystems
- Ensure the remote user owns ~/.waveterm
When it happens
Trigger: os.Symlink(impl.SockName, symlinkPath) fails: path already exists as a file/dir, stale dangling symlink the OS still refuses, unsupported filesystem (Windows/FAT), or missing parent dir permissions despite MkdirAll.
Common situations: Leftover symlink from a crashed previous session on a filesystem that disallows overwrite (os.Remove raced or failed silently), NFS/SSHFS mounts without symlink support, read-only ~/.waveterm dir.
Related errors
- starting file stream: %w
- failed to get app directory: %w
- failed to get builder executable path: %w
- build output not found: %w
- failed to read app manifest: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/f9ae809106e3351f.
Report an issue: GitHub.