{"record":{"id":"7bdea818e240bafc","repo":"louislam/dockge","slug":"service-name-must-be-a-string","errorCode":null,"errorMessage":"Service name must be a string.","messagePattern":"Service name must be a string\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"backend/agent-socket-handlers/terminal-socket-handler.ts","lineNumber":96,"sourceCode":"                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({\n                    ok: true,\n                }, callback);\n            } catch (e) {\n                callbackError(e, callback);","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/louislam/dockge/blob/f809ae192b571944ad773e9866d3e67064ae8043/backend/agent-socket-handlers/terminal-socket-handler.ts#L78-L114","documentation":"Thrown as a ValidationError in the interactiveTerminal handler when the serviceName argument is not a string. Like the other checks in this handler it validates raw socket input before resolving the stack service that will host the shell.","triggerScenarios":"Emitting 'interactiveTerminal' with a second argument (serviceName) that is null, undefined, a number, or an object instead of a string.","commonSituations":"Service dropdown empty (no services in the stack), client passing a service object rather than its name, or a UI bug where no service is chosen before opening the terminal.","solutions":["Pass the service name as a string, e.g. socket.emit('interactiveTerminal', stackName, service.name, shell, cb).","Ensure a service is selected/available in the UI before opening the terminal.","Check stack definition includes services and the client receives them correctly.","Coerce only after verifying the value is defined (String(serviceName))."],"exampleFix":"// before\nsocket.emit(\"interactiveTerminal\", stackName, undefined, shell, cb);\n// after\nconst serviceName = selectedService?.name;\nif (typeof serviceName === \"string\") {\n    socket.emit(\"interactiveTerminal\", stackName, serviceName, shell, cb);\n}","handlingStrategy":"type-guard","validationCode":"if (typeof serviceName !== \"string\" || serviceName === \"\") { showError(\"Select a service\"); return; }\nsocket.emit(\"interactiveTerminal\", stackName, serviceName, shell, cb);","typeGuard":"const isNonEmptyString = (v) => typeof v === \"string\" && v.length > 0;","tryCatchPattern":"socket.emit(\"interactiveTerminal\", stackName, serviceName, shell, (res) => { if (res?.error) showError(res.error.message); });","preventionTips":["Require a service selection before opening a terminal.","Pass service.name, not the service object.","Check the stack actually has services before rendering the terminal UI.","Validate emit args centrally in a wrapper."],"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-31T19:17:28.585Z"}