{"record":{"id":"9362074b0f7f8022","repo":"gastownhall/beads","slug":"external-reference-missing-project-name","errorCode":null,"errorMessage":"external reference missing project name","messagePattern":"external reference missing project name","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/dep.go","lineNumber":1502,"sourceCode":"}\n\n// validateExternalRef validates the format of an external dependency reference.\n// Valid format: external:<project>:<capability>\nfunc validateExternalRef(ref string) error {\n\tif !strings.HasPrefix(ref, \"external:\") {\n\t\treturn fmt.Errorf(\"external reference must start with 'external:'\")\n\t}\n\n\tparts := strings.SplitN(ref, \":\", 3)\n\tif len(parts) != 3 {\n\t\treturn fmt.Errorf(\"invalid external reference format: expected 'external:<project>:<capability>', got '%s'\", ref)\n\t}\n\n\tproject := parts[1]\n\tcapability := parts[2]\n\n\tif project == \"\" {\n\t\treturn fmt.Errorf(\"external reference missing project name\")\n\t}\n\tif capability == \"\" {\n\t\treturn fmt.Errorf(\"external reference missing capability name\")\n\t}\n\n\treturn nil\n}\n\n// IsExternalRef returns true if the dependency reference is an external reference.\nfunc IsExternalRef(ref string) bool {\n\treturn strings.HasPrefix(ref, \"external:\")\n}\n\n// ParseExternalRef parses an external reference into project and capability.\n// Returns empty strings if the format is invalid.\nfunc ParseExternalRef(ref string) (project, capability string) {\n\tif !IsExternalRef(ref) {\n\t\treturn \"\", \"\"","sourceCodeStart":1484,"sourceCodeEnd":1520,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/dep.go#L1484-L1520","documentation":"validateExternalRef requires a non-empty project segment after the 'external:' prefix. A ref shaped like 'external::capability' (empty project) fails with this message. The project names the foreign project the dependency points into.","triggerScenarios":"Supplying 'external::deploy' or 'external: :deploy' — the ref has the prefix and three parts, but parts[1] is empty or whitespace-only in intent.","commonSituations":"Template/variable interpolation that left the project blank ($PROJECT unset in a script producing 'external:$PROJECT:deploy'); copy-paste dropping the project name; config file with an empty project key.","solutions":["Insert the project name: external:<project>:<capability>, e.g. external:infra:deploy.","Check the shell variable or config field feeding the project segment and ensure it is set and non-empty.","Validate refs in scripts before invoking: test that the project part between the first two colons is non-empty."],"exampleFix":"// before (PROJECT empty in CI)\nbd dep add bd-1 \"external:${PROJECT}:deploy\"  # -> external::deploy\n\n// after\n: \"${PROJECT:?PROJECT must be set}\"\nbd dep add bd-1 \"external:${PROJECT}:deploy\"","handlingStrategy":"validation","validationCode":"func hasProjectSegment(ref string) bool {\n\tparts := strings.SplitN(strings.TrimPrefix(ref, \"external:\"), \":\", 3)\n\treturn len(parts) == 3 && strings.TrimSpace(parts[0]) != \"\"\n}","typeGuard":null,"tryCatchPattern":"if err := validateExternalRef(ref); err != nil {\n\tif strings.Contains(err.Error(), \"missing project name\") {\n\t\treturn fmt.Errorf(\"set PROJECT env/config before composing external ref %q\", ref)\n\t}\n\treturn err\n}","preventionTips":["Fail fast in scripts when the project variable is unset (bash :? expansion).","Default the project from a config file rather than an optional env var.","Validate composed refs before invoking bd dep add."],"tags":["validation","external-references","dependencies"],"backgroundTag":"invalid-reference-format","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}