{"record":{"id":"0c515c063d4da77f","repo":"anomalyco/sst","slug":"at-least-one-condition-path-query-or-header-mu","errorCode":null,"errorMessage":"At least one condition (path, query, or header) must be set for rules on an external ALB in Service \"${name}\".","messagePattern":"At least one condition \\(path, query, or header\\) must be set for rules on an external ALB in Service \"(.+?)\"\\.","errorType":"validation","errorClass":"VisibleError","httpStatus":null,"severity":"error","filePath":"platform/src/components/aws/service.ts","lineNumber":2746,"sourceCode":"          );\n        }\n\n        const seen =\n          prioritiesByListener.get(rule.listen) ?? new Set();\n        if (seen.has(rule.priority)) {\n          throw new VisibleError(\n            `Duplicate priority ${rule.priority} on listener \"${rule.listen}\" in Service \"${name}\".`,\n          );\n        }\n        seen.add(rule.priority);\n        prioritiesByListener.set(rule.listen, seen);\n\n        if (\n          !rule.conditions?.path &&\n          !rule.conditions?.query &&\n          !rule.conditions?.header\n        ) {\n          throw new VisibleError(\n            `At least one condition (path, query, or header) must be set for rules on an external ALB in Service \"${name}\".`,\n          );\n        }\n\n        const listenerParts = rule.listen.split(\"/\");\n        const listenerPort = parseInt(listenerParts[0]);\n        const listenerProtocol = listenerParts[1];\n\n        const forwardParts = rule.forward.split(\"/\");\n        const forwardPort = parseInt(forwardParts[0]);\n        const forwardProtocol = forwardParts[1].toUpperCase();\n        const containerNameForKey = rule.container ?? name;\n        const tgtId = targetKey(containerNameForKey, forwardProtocol, forwardPort);\n\n        const targetGroup = albTargets[tgtId];\n        if (!targetGroup) {\n          throw new VisibleError(\n            `Target group \"${tgtId}\" not found. Ensure the forward port matches in Service \"${name}\".`,","sourceCodeStart":2728,"sourceCodeEnd":2764,"githubUrl":"https://github.com/anomalyco/sst/blob/a0bd20f762883e72a35caccb4896c42ce5b3f707/platform/src/components/aws/service.ts#L2728-L2764","documentation":"Unlike an SST-managed ALB where a rule can act as a default catch-all, rules on an external/shared ALB must be distinguishable so they can be translated into AWS listener conditions. Each rule therefore needs at least one of path, query, or header conditions.","triggerScenarios":"An ALB attachment rule specifying only listen (and maybe container/forward) with conditions omitted or conditions set to an empty object/undefined fields.","commonSituations":"Porting rules from a self-managed Service (where catch-all is fine) to a shared ALB; assuming a default rule is created on external listeners; typing conditions but leaving all three sub-fields empty.","solutions":["Add conditions: { path: \"/*\" } (or a specific path pattern) to the rule","Add a query or header condition if path-based routing doesn't fit","If a catch-all is genuinely needed, own the default listener rule outside per-service rules"],"exampleFix":"// before\nrules: [{ listen: \"443/https\", container: \"app\" }]\n// after\nrules: [{ listen: \"443/https\", container: \"app\", conditions: { path: \"/*\" } }]","handlingStrategy":"validation","validationCode":"for (const r of attachment.rules) {\n  const c = r.conditions ?? {};\n  if (!c.path && !c.query && !c.header)\n    throw new Error(`rule on ${r.listen} needs a path, query, or header condition`);\n}","typeGuard":"const hasCondition = (r: { conditions?: { path?: string; query?: Record<string, string>; header?: Record<string, string> } }) =>\n  Boolean(r.conditions?.path || r.conditions?.query || r.conditions?.header);","tryCatchPattern":"null","preventionTips":["Default new external-ALB rules to conditions: { path: \"/*\" }","Only allow catch-all rules on SST-managed load balancers","Require conditions in your zod/config schema for external attachments"],"tags":["load-balancer","alb","validation","routing"],"backgroundTag":"missing-required-config","analyzedSha":"a0bd20f762883e72a35caccb4896c42ce5b3f707","analyzedAt":"2026-08-30T11:26:00.383Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}