{"record":{"id":"6d1909f8042277e3","repo":"louislam/dockge","slug":"stack-name-must-be-a-string-6d1909","errorCode":null,"errorMessage":"Stack name must be a string.","messagePattern":"Stack name must be a string\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"backend/agent-socket-handlers/terminal-socket-handler.ts","lineNumber":92,"sourceCode":"        // Check if MainTerminal is enabled\n        agentSocket.on(\"checkMainTerminal\", async (callback) => {\n            try {\n                checkLogin(socket);\n                callbackResult({\n                    ok: server.config.enableConsole,\n                }, callback);\n            } catch (e) {\n                callbackError(e, callback);\n            }\n        });\n\n        // Interactive Terminal for containers\n        agentSocket.on(\"interactiveTerminal\", async (stackName : unknown, serviceName : unknown, shell : unknown, callback) => {\n            try {\n                checkLogin(socket);\n\n                if (typeof(stackName) !== \"string\") {\n                    throw new ValidationError(\"Stack name must be a string.\");\n                }\n\n                if (typeof(serviceName) !== \"string\") {\n                    throw new ValidationError(\"Service name must be a string.\");\n                }\n\n                if (typeof(shell) !== \"string\") {\n                    throw new ValidationError(\"Shell must be a string.\");\n                }\n\n                log.debug(\"interactiveTerminal\", \"Stack name: \" + stackName);\n                log.debug(\"interactiveTerminal\", \"Service name: \" + serviceName);\n\n                // Get stack\n                const stack = await Stack.getStack(server, stackName);\n                stack.joinContainerTerminal(socket, serviceName, shell);\n\n                callbackResult({","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/louislam/dockge/blob/f809ae192b571944ad773e9866d3e67064ae8043/backend/agent-socket-handlers/terminal-socket-handler.ts#L74-L110","documentation":"Thrown as a ValidationError in the interactiveTerminal handler when the stackName argument is not a string. The handler validates all raw socket arguments before using them to look up a Docker/Compose stack. It prevents type-confusion when the client sends malformed data.","triggerScenarios":"Emitting 'interactiveTerminal' with a first argument that is not a string (null, undefined, number, object) while the remaining args (serviceName, shell) would otherwise be valid.","commonSituations":"Client select/dropdown bound to a stack object instead of its name string; stack list not yet loaded so the value is undefined; JSON round-tripping changing types.","solutions":["Pass the stack's name string, not the stack object: socket.emit('interactiveTerminal', stack.name, serviceName, shell, cb).","Verify the stack list has loaded and a stack is selected before opening a terminal.","Stringify/coerce deliberately (String(stackName)) after confirming it is defined.","Handle the callback error to show the user which argument was invalid."],"exampleFix":"// before\nsocket.emit(\"interactiveTerminal\", stack, serviceName, \"/bin/sh\", cb);\n// after\nsocket.emit(\"interactiveTerminal\", stack.name, serviceName, \"/bin/sh\", cb);","handlingStrategy":"type-guard","validationCode":"if (typeof stack?.name !== \"string\") { showError(\"Select a stack first\"); return; }\nsocket.emit(\"interactiveTerminal\", stack.name, serviceName, shell, cb);","typeGuard":"const isStackRef = (s) => typeof s === \"string\" || (s && typeof s.name === \"string\");","tryCatchPattern":"socket.emit(\"interactiveTerminal\", stackName, serviceName, shell, (res) => { if (res?.error) showError(res.error.message); });","preventionTips":["Pass stack.name (string), never the stack object.","Disable the terminal button until a stack is selected and loaded.","Validate all three string args before emitting.","Use a typed emit helper for stack-related events."],"tags":["validation","typescript","socket-io","docker","terminal"],"backgroundTag":"invalid-socket-payload-type","analyzedSha":"f809ae192b571944ad773e9866d3e67064ae8043","analyzedAt":"2026-08-31T19:13:50.919Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}