{"record":{"id":"37f61c50e2f17825","repo":"wavetermdev/waveterm","slug":"invalid-direction-direction","errorCode":null,"errorMessage":"Invalid direction: ${direction}","messagePattern":"Invalid direction: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/layout/lib/layoutTree.ts","lineNumber":216,"sourceCode":"                        index: indexInParent() + 1,\n                        node: nodeToMove,\n                    };\n            }\n            break;\n        case DropDirection.Center:\n            if (nodeId !== rootNode.id && nodeToMoveId !== rootNode.id) {\n                const swapAction: LayoutTreeSwapNodeAction = {\n                    type: LayoutTreeActionType.Swap,\n                    node1Id: nodeId,\n                    node2Id: nodeToMoveId,\n                };\n                return swapAction;\n            } else {\n                console.warn(\"cannot swap\");\n            }\n            break;\n        default:\n            throw new Error(`Invalid direction: ${direction}`);\n    }\n\n    if (\n        newMoveOperation?.parentId !== nodeToMoveParent()?.id ||\n        (newMoveOperation.index !== nodeToMoveIndexInParent() &&\n            newMoveOperation.index !== nodeToMoveIndexInParent() + 1)\n    )\n        return {\n            type: LayoutTreeActionType.Move,\n            ...newMoveOperation,\n        } as LayoutTreeMoveNodeAction;\n}\n\nexport function moveNode(layoutState: LayoutTreeState, action: LayoutTreeMoveNodeAction) {\n    console.log(\"moveNode\", layoutState, action);\n    const rootNode = layoutState.rootNode;\n    if (!action) {\n        console.error(\"no move node action provided\");","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/frontend/layout/lib/layoutTree.ts#L198-L234","documentation":"computeMoveNode translates a keyboard/mouse move direction (left/right/up/down/swap etc.) into a MoveNodeOperation. A direction value that reaches the switch's default branch has no mapping, so the function throws rather than silently ignoring the move.","triggerScenarios":"Calling moveNode/computeMoveNode with a direction string not covered by the switch cases (e.g. an unknown literal, undefined due to a bad event mapping).","commonSituations":"New direction enum value added to the UI but not handled in layoutTree.ts; keybinding sends an unhandled direction; stale serialized pendingAction with an obsolete direction value.","solutions":["Check which direction value triggered it and add a case for it in computeMoveNode's switch","Fix the caller/keybinding sending an invalid direction literal","Guard the call site with a whitelist check before dispatching the move action"],"exampleFix":"// before\nmoveNode(direction as Direction);\n\n// after\nconst VALID = [\"left\", \"right\", \"up\", \"down\", \"swap\"];\nif (VALID.includes(direction)) moveNode(direction);","handlingStrategy":"validation","validationCode":"const VALID = [\"left\", \"right\", \"up\", \"down\", \"swap\"] as const;\ntype Dir = typeof VALID[number];\nif (!VALID.includes(direction as Dir)) return; // ignore invalid move","typeGuard":"function isMoveDirection(d: string): d is \"left\"|\"right\"|\"up\"|\"down\"|\"swap\" {\n    return [\"left\",\"right\",\"up\",\"down\",\"swap\"].includes(d);\n}","tryCatchPattern":"try {\n    computeMoveNode(tree, direction);\n} catch (e) {\n    if (String(e.message).startsWith(\"Invalid direction\")) {\n        console.warn(\"unhandled move direction:\", e.message);\n    } else { throw e; }\n}","preventionTips":["Use a string-literal union type for directions so the compiler flags unhandled values","Update computeMoveNode's switch whenever a new direction is added to the UI","Exhaustiveness-check with a never-typed default case instead of throwing raw"],"tags":["layout","invalid-argument","switch-default"],"backgroundTag":"invalid-direction-value","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}