gastownhall/beads · error

external reference missing project name

Error message

external reference missing project name

What it means

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.

Source

Thrown at cmd/bd/dep.go:1502

}

// validateExternalRef validates the format of an external dependency reference.
// Valid format: external:<project>:<capability>
func validateExternalRef(ref string) error {
	if !strings.HasPrefix(ref, "external:") {
		return fmt.Errorf("external reference must start with 'external:'")
	}

	parts := strings.SplitN(ref, ":", 3)
	if len(parts) != 3 {
		return fmt.Errorf("invalid external reference format: expected 'external:<project>:<capability>', got '%s'", ref)
	}

	project := parts[1]
	capability := parts[2]

	if project == "" {
		return fmt.Errorf("external reference missing project name")
	}
	if capability == "" {
		return fmt.Errorf("external reference missing capability name")
	}

	return nil
}

// IsExternalRef returns true if the dependency reference is an external reference.
func IsExternalRef(ref string) bool {
	return strings.HasPrefix(ref, "external:")
}

// ParseExternalRef parses an external reference into project and capability.
// Returns empty strings if the format is invalid.
func ParseExternalRef(ref string) (project, capability string) {
	if !IsExternalRef(ref) {
		return "", ""

View on GitHub (pinned to 71377f2769)

Solutions

  1. Insert the project name: external:<project>:<capability>, e.g. external:infra:deploy.
  2. Check the shell variable or config field feeding the project segment and ensure it is set and non-empty.
  3. Validate refs in scripts before invoking: test that the project part between the first two colons is non-empty.

Example fix

// before (PROJECT empty in CI)
bd dep add bd-1 "external:${PROJECT}:deploy"  # -> external::deploy

// after
: "${PROJECT:?PROJECT must be set}"
bd dep add bd-1 "external:${PROJECT}:deploy"
Defensive patterns

Strategy: validation

Validate before calling

func hasProjectSegment(ref string) bool {
	parts := strings.SplitN(strings.TrimPrefix(ref, "external:"), ":", 3)
	return len(parts) == 3 && strings.TrimSpace(parts[0]) != ""
}

Try / catch

if err := validateExternalRef(ref); err != nil {
	if strings.Contains(err.Error(), "missing project name") {
		return fmt.Errorf("set PROJECT env/config before composing external ref %q", ref)
	}
	return err
}

Prevention

When it happens

Trigger: Supplying 'external::deploy' or 'external: :deploy' — the ref has the prefix and three parts, but parts[1] is empty or whitespace-only in intent.

Common situations: 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.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/9362074b0f7f8022. Report an issue: GitHub.