{"record":{"id":"414fd40d84ee9f94","repo":"FlowiseAI/Flowise","slug":"invalid-app-slug-format-must-be-lowercase-letters","errorCode":null,"errorMessage":"Invalid app slug format. Must be lowercase letters, digits, hyphens and underscores only.","messagePattern":"Invalid app slug format\\. Must be lowercase letters, digits, hyphens and underscores only\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/components/nodes/tools/MCP/Pipedream/PipedreamMCP.ts","lineNumber":266,"sourceCode":"        const databaseEntities = options.databaseEntities as IDatabaseEntity\n        const optionsWithWorkspaceId = options.workspaceId ? options : { ...options, workspaceId }\n        const variables = await getVars(appDataSource, databaseEntities, nodeData, optionsWithWorkspaceId)\n        const vars = prepareSandboxVars(variables) as Record<string, string>\n\n        return value.replace(VAR_PLACEHOLDER_RE, (match, varName) => {\n            return vars[varName] != null ? String(vars[varName]) : match\n        })\n    }\n\n    async getTools(nodeData: INodeData, options: ICommonObject, isLoadMethod = false): Promise<Tool[]> {\n        const appSlug = nodeData.inputs?.appSlug as string\n        if (!appSlug) {\n            throw new Error('Pipedream app slug is required')\n        }\n\n        const SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9_-]{0,98}[a-z0-9])?(?:,\\s*[a-z0-9](?:[a-z0-9_-]{0,98}[a-z0-9])?)*$/\n        if (!SLUG_PATTERN.test(appSlug)) {\n            throw new Error('Invalid app slug format. Must be lowercase letters, digits, hyphens and underscores only.')\n        }\n\n        let externalUserId = nodeData.inputs?.externalUserId as string\n        externalUserId = await this.resolveVarsInString(externalUserId, nodeData, options)\n\n        if (externalUserId.includes('{{')) {\n            if (!isLoadMethod) {\n                throw new Error(\n                    'Variables in User ID are not resolved. ' +\n                        '{{$vars.*}} requires a matching workspace variable. ' +\n                        '{{$flow.*}} variables (e.g. sessionId) are only available at runtime, not when refreshing actions.'\n                )\n            }\n            // For loadMethods context, use a sanitized fallback so tool listing still works.\n            // The actual externalUserId will be resolved at runtime.\n            externalUserId = 'flowise_preview_user'\n        }\n","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/components/nodes/tools/MCP/Pipedream/PipedreamMCP.ts#L248-L284","documentation":"Thrown when the appSlug is present but fails the SLUG_PATTERN regex (lowercase letters/digits, hyphens, underscores; allows comma-separated lists). This guards the x-pd-app-slug header against injection and malformed values before the request is sent.","triggerScenarios":"appSlug contains uppercase letters, spaces, special characters, slashes, or shell metacharacters; a multi-slug list with a bad entry; user pasted a full URL or app name instead of the slug.","commonSituations":"User typed 'Slack' (uppercase) instead of 'slack'; pasted 'https://...' or a display name; used a comma list like 'slack, github' where one entry has a space; template injection introduced a bad character.","solutions":["Lowercase the slug and remove spaces: use the exact identifier from Pipedream's app directory.","For multiple apps, comma-separate valid slugs without spaces after commas is tolerated but keep each entry clean.","If the value comes from a variable, sanitize/normalize it before it reaches the node input."],"exampleFix":"// before: appSlug = 'Slack App'\n// after:  appSlug = 'slack'","handlingStrategy":"validation","validationCode":"const SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9_-]{0,98}[a-z0-9])?(?:,\\s*[a-z0-9](?:[a-z0-9_-]{0,98}[a-z0-9])?)*$/\nconst appSlug = (nodeData.inputs?.appSlug as string || '').trim().toLowerCase()\nif (!SLUG_PATTERN.test(appSlug)) {\n    throw new Error('Invalid app slug format')\n}","typeGuard":"function isValidPipedreamSlug(slug: string): boolean {\n    return /^[a-z0-9](?:[a-z0-9_-]{0,98}[a-z0-9])?(?:,\\s*[a-z0-9](?:[a-z0-9_-]{0,98}[a-z0-9])?)*$/.test(slug)\n}","tryCatchPattern":"try { await pipedream.getTools(nodeData, options) }\ncatch (e) { if (e instanceof Error && e.message.startsWith('Invalid app slug format')) { /* normalize the input */ } }","preventionTips":["Normalize (trim + lowercase) the slug in the UI before saving.","Show inline regex validation on the appSlug field."],"tags":["pipedream","validation","input-sanitization","regex"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}