{"record":{"id":"eb9d6909271bca5a","repo":"wavetermdev/waveterm","slug":"swaptoken-is-required-in-commandoptstype","errorCode":null,"errorMessage":"SwapToken is required in CommandOptsType","messagePattern":"SwapToken is required in CommandOptsType","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/shellexec/shellexec.go","lineNumber":178,"sourceCode":"\n\tif termSize.Rows == 0 || termSize.Cols == 0 {\n\t\ttermSize.Rows = shellutil.DefaultTermRows\n\t\ttermSize.Cols = shellutil.DefaultTermCols\n\t}\n\tif termSize.Rows <= 0 || termSize.Cols <= 0 {\n\t\treturn nil, fmt.Errorf(\"invalid term size: %v\", termSize)\n\t}\n\tcmdPty, err := pty.StartWithSize(ecmd, &pty.Winsize{Rows: uint16(termSize.Rows), Cols: uint16(termSize.Cols)})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcmdWrap := MakeCmdWrap(ecmd, cmdPty, true)\n\treturn &ShellProc{Cmd: cmdWrap, ConnName: conn.GetName(), CloseOnce: &sync.Once{}, DoneCh: make(chan any)}, nil\n}\n\nfunc StartWslShellProc(ctx context.Context, termSize waveobj.TermSize, cmdStr string, cmdOpts CommandOptsType, conn *wslconn.WslConn) (*ShellProc, error) {\n\tif cmdOpts.SwapToken == nil {\n\t\treturn nil, fmt.Errorf(\"SwapToken is required in CommandOptsType\")\n\t}\n\tclient := conn.GetClient()\n\tconn.Infof(ctx, \"WSL-NEWSESSION (StartWslShellProc)\")\n\tconnRoute := wshutil.MakeConnectionRouteId(conn.GetName())\n\trpcClient := wshclient.GetBareRpcClient()\n\tremoteInfo, err := wshclient.RemoteGetInfoCommand(rpcClient, &wshrpc.RpcOpts{Route: connRoute, Timeout: 2000})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to obtain client info: %w\", err)\n\t}\n\tlog.Printf(\"client info collected: %+#v\", remoteInfo)\n\tvar shellPath string\n\tif cmdOpts.ShellPath != \"\" {\n\t\tconn.Infof(ctx, \"using shell path from command opts: %s\\n\", cmdOpts.ShellPath)\n\t\tshellPath = cmdOpts.ShellPath\n\t}\n\tconfigShellPath := conn.GetConfigShellPath()\n\tif shellPath == \"\" && configShellPath != \"\" {\n\t\tconn.Infof(ctx, \"using shell path from config (conn:shellpath): %s\\n\", configShellPath)","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/shellexec/shellexec.go#L160-L196","documentation":"StartWslShellProc requires cmdOpts.SwapToken to be non-nil because the WSL session bootstrap exchanges a swap token with the remote wsh server. If the token is missing it returns \"SwapToken is required in CommandOptsType\" instead of starting a session that could not be authenticated/handed off.","triggerScenarios":"Calling StartWslShellProc with a CommandOptsType whose SwapToken field is nil — i.e. the caller did not generate the secret used by the wsh swap handshake for WSL connections.","commonSituations":"Code path intended for local/SSH shells reused for WSL without setting SwapToken; a refactor that dropped swap-token generation in setupAndStartShellProcess.","solutions":["Generate and set cmdOpts.SwapToken before calling StartWslShellProc (use the same token generation the WSH setup path uses)","Route WSL connections through the correct setup path that populates SwapToken","If a no-wsh session is intended, call StartWslShellProcNoWsh instead"],"exampleFix":"// before\nvar cmdOpts shellexec.CommandOptsType // SwapToken nil\nproc, err := shellexec.StartWslShellProc(ctx, termSize, cmdStr, cmdOpts, conn)\n// after\ncmdOpts.SwapToken = &swapToken // generate via the wsh swap-token helper\nproc, err := shellexec.StartWslShellProc(ctx, termSize, cmdStr, cmdOpts, conn)","handlingStrategy":"validation","validationCode":"if cmdOpts.SwapToken == nil {\n    return fmt.Errorf(\"cannot start WSL shell: SwapToken not set\")\n}\nproc, err := shellexec.StartWslShellProc(ctx, termSize, cmdStr, cmdOpts, conn)","typeGuard":"func hasSwapToken(o shellexec.CommandOptsType) bool {\n    return o.SwapToken != nil\n}","tryCatchPattern":"proc, err := shellexec.StartWslShellProc(ctx, termSize, cmdStr, cmdOpts, conn)\nif err != nil && err.Error() == \"SwapToken is required in CommandOptsType\" {\n    // caller bug: fix setup path, not retryable\n    return err\n}","preventionTips":["Always populate SwapToken for WSL shell starts","Centralize WSL process setup in one path that sets the token","Use StartWslShellProcNoWsh when no wsh handshake is desired"],"tags":["go","wsl","wsh","swap-token","validation"],"backgroundTag":"missing-required-option","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}