{"record":{"id":"ec8308e2b8d3a3e6","repo":"wavetermdev/waveterm","slug":"open-and-openexternal-cannot-both-be-true","errorCode":null,"errorMessage":"open and openExternal cannot both be true","messagePattern":"open and openExternal cannot both be true","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshrpc/wshserver/wshserver.go","lineNumber":1428,"sourceCode":"\treturn filestore.WFS.WriteFile(ctx, data.ZoneId, data.FileName, []byte(envStr))\n}\n\nfunc (ws *WshServer) PathCommand(ctx context.Context, data wshrpc.PathCommandData) (string, error) {\n\tpathType := data.PathType\n\topenInternal := data.Open\n\topenExternal := data.OpenExternal\n\tvar path string\n\tswitch pathType {\n\tcase \"config\":\n\t\tpath = wavebase.GetWaveConfigDir()\n\tcase \"data\":\n\t\tpath = wavebase.GetWaveDataDir()\n\tcase \"log\":\n\t\tpath = filepath.Join(wavebase.GetWaveDataDir(), \"waveapp.log\")\n\t}\n\n\tif openInternal && openExternal {\n\t\treturn \"\", fmt.Errorf(\"open and openExternal cannot both be true\")\n\t}\n\n\tif openInternal {\n\t\t_, err := ws.CreateBlockCommand(ctx, wshrpc.CommandCreateBlockData{\n\t\t\tTabId: data.TabId,\n\t\t\tBlockDef: &waveobj.BlockDef{Meta: map[string]any{\n\t\t\t\twaveobj.MetaKey_View: \"preview\",\n\t\t\t\twaveobj.MetaKey_File: path,\n\t\t\t}},\n\t\t\tEphemeral: true,\n\t\t\tFocused:   true,\n\t\t})\n\n\t\tif err != nil {\n\t\t\treturn path, fmt.Errorf(\"error opening path: %w\", err)\n\t\t}\n\t} else if openExternal {\n\t\terr := open.Run(path)","sourceCodeStart":1410,"sourceCodeEnd":1446,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshrpc/wshserver/wshserver.go#L1410-L1446","documentation":"PathCommand (pkg/wshrpc/wshserver/wshserver.go:1413) resolves a Wave directory path (config, data, or log) and can open it either in an internal preview block (Open) or via the OS default handler (OpenExternal). These two open modes are mutually exclusive, so the command rejects requests with both flags set rather than picking one arbitrarily. This is a pure client-side request validation error; no I/O occurs before it.","triggerScenarios":"Calling the wsh `path` RPC (or CLI `wsh path --open --open-external <type>`) with both PathCommandData.Open and PathCommandData.OpenExternal = true. PathType may be any of \"config\", \"data\", or \"log\" — the check happens before path resolution matters.","commonSituations":"CLI/shell aliases that accumulate open flags; scripts that set both flags by default with environment toggles; UI code passing user checkboxes for both 'open in Wave' and 'open in system app' without mutual exclusion.","solutions":["Set only one of Open or OpenExternal to true in the PathCommandData before invoking the RPC.","In CLI usage, pass only one of --open or --open-external.","In wrapping code, add a guard that clears OpenExternal when Open is set (or return your own validation error) before calling PathCommand."],"exampleFix":"// before\nwshclient.PathCommand(ctx, wshrpc.PathCommandData{PathType: \"log\", Open: true, OpenExternal: true})\n// after\nwshclient.PathCommand(ctx, wshrpc.PathCommandData{PathType: \"log\", Open: true})","handlingStrategy":"validation","validationCode":"if data.Open && data.OpenExternal {\n    return fmt.Errorf(\"specify only one of Open or OpenExternal\")\n}\n// safe to call wshclient.PathCommand(ctx, data)","typeGuard":null,"tryCatchPattern":"resp, err := wshclient.PathCommand(ctx, data)\nif err != nil && strings.Contains(err.Error(), \"open and openExternal cannot both be true\") {\n    data.OpenExternal = false\n    resp, err = wshclient.PathCommand(ctx, data)\n}","preventionTips":["In UI code, make 'open internal' and 'open external' mutually exclusive controls (radio buttons).","Centralize PathCommandData construction in one helper that normalizes the flags.","Audit CLI wrappers for flags that can be combined."],"tags":["validation","rpc","waveterm"],"backgroundTag":"mutually-exclusive-flags","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}