{"record":{"id":"c51720beade8f300","repo":"louislam/uptime-kuma","slug":"slug-must-be-string","errorCode":null,"errorMessage":"Slug must be string","messagePattern":"Slug must be string","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"server/socket-handlers/status-page-socket-handler.js","lineNumber":535,"sourceCode":"        } catch (error) {\n            callback({\n                ok: false,\n                msg: error.message,\n            });\n        }\n    });\n};\n\n/**\n * Check slug a-z, 0-9, - only\n * Regex from: https://stackoverflow.com/questions/22454258/js-regex-string-validation-for-slug\n * @param {string} slug Slug to test\n * @returns {void}\n * @throws Slug is not valid\n */\nfunction checkSlug(slug) {\n    if (typeof slug !== \"string\") {\n        throw new Error(\"Slug must be string\");\n    }\n\n    slug = slug.trim();\n\n    if (!slug) {\n        throw new Error(\"Slug cannot be empty\");\n    }\n\n    if (!slug.match(/^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$/)) {\n        throw new Error(\"Invalid Slug\");\n    }\n}\n","sourceCodeStart":517,"sourceCodeEnd":548,"githubUrl":"https://github.com/louislam/uptime-kuma/blob/6b5ea0155793e666666745fb8d6fef1e829543a2/server/socket-handlers/status-page-socket-handler.js#L517-L548","documentation":"Thrown by checkSlug() inside the status-page socket handler. The function guards its first branch with `typeof slug !== \"string\"`, so any non-string value (number, boolean, array, object, null, undefined) is rejected before slug formatting rules run. It exists because slug values are used directly in SQL queries (R.findOne(\"status_page\", \" slug = ? \", [slug])) and as URL path segments, where a non-string would corrupt downstream logic.","triggerScenarios":"Emitting the socket event `saveStatusPage(slug, config, imgDataUrl, publicGroupList, callback)` with a `config.slug` that is not a string (e.g. a number, null, undefined, or object). checkSlug is invoked at status-page-socket-handler.js:303 on `config.slug`. The `createStatusPage` path (line 456) pre-checks `typeof slug !== \"string\"` with a different message (\"Slug -Accept string only\"), so this specific message is reached only via saveStatusPage.","commonSituations":"A custom/programmatic socket client that omits slug or sends it as a number; a frontend regression where the slug input binds to a numeric model; corrupt status page config loaded from storage; an integration test that passes a raw number instead of a stringified slug.","solutions":["Ensure config.slug is a string before emitting saveStatusPage: `String(config.slug)`.","Validate the slug client-side with the same regex `^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$` before submission.","If you operate the socket programmatically, double-check the payload shape against the handler signature: (slug, config, imgDataUrl, publicGroupList, callback).","Add a typeof guard in your caller so an empty/missing slug short-circuits with a user-friendly message instead of reaching the server."],"exampleFix":"// before\nsocket.emit(\"saveStatusPage\", slug, { slug: 123, title }, ...);\n\n// after\nconst safeSlug = typeof config.slug === \"string\" ? config.slug : String(config.slug ?? \"\");\nsocket.emit(\"saveStatusPage\", slug, { ...config, slug: safeSlug }, ...);","handlingStrategy":"type-guard","validationCode":"function isStringSlug(v) { return typeof v === \"string\"; }\nif (!isStringSlug(config.slug)) { throw new TypeError(\"slug must be a string\"); }\ncheckSlug(config.slug);","typeGuard":"const isString = (v) => typeof v === \"string\";","tryCatchPattern":"try { checkSlug(config.slug); } catch (e) { callback({ ok: false, msg: e.message }); return; }","preventionTips":["Always stringify the slug at the source before building the socket payload.","Keep a single slugify/isStringSlug helper shared by create and save paths.","Type the payload in TS so a non-string slug fails at compile time."],"tags":["status-page","slug","validation","socket","uptime-kuma"],"backgroundTag":null,"analyzedSha":"6b5ea0155793e666666745fb8d6fef1e829543a2","analyzedAt":"2026-08-12T23:42:12.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}