gastownhall/beads · error

invalid external reference format: expected 'external:<proje

Error message

invalid external reference format: expected 'external:<project>:<capability>', got '%s'

What it means

After confirming the 'external:' prefix, validateExternalRef splits the remainder on ':' and requires exactly three parts. If the ref does not match external:<project>:<capability>, this error reports the expected format and echoes the offending value.

Source

Thrown at cmd/bd/dep.go:1495

			line += " " + ui.FailStyle.Bold(true).Render("[BLOCKED]")
		} else {
			line += " " + ui.PassStyle.Bold(true).Render("[READY]")
		}
	}

	return line
}

// 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:")

View on GitHub (pinned to 71377f2769)

Solutions

  1. Restructure the ref to exactly two segments after the prefix: external:<project>:<capability>.
  2. Replace ':' inside capability names with '-' or another separator, e.g. external:myproject:api-v2 instead of external:myproject:api:v2.
  3. Ensure the project and capability segments are both non-empty (see errors 345/346).

Example fix

// before
validateExternalRef("external:myproject")  // only one segment

// after
validateExternalRef("external:myproject:deploy-api")
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

func asExternalRef(ref string) (project, capability string, ok bool) {
	if !strings.HasPrefix(ref, "external:") { return "", "", false }
	parts := strings.SplitN(strings.TrimPrefix(ref, "external:"), ":", 3)
	if len(parts) != 3 { return "", "", false }
	return parts[0], parts[1], true
}

Try / catch

if err := validateExternalRef(ref); err != nil {
	if strings.HasPrefix(err.Error(), "invalid external reference format") {
		fmt.Fprintf(os.Stderr, "fix ref %q to external:<project>:<capability>\n", ref)
	}
	return err
}

Prevention

When it happens

Trigger: Passing an external ref with the wrong number of colons to the external dependency path: 'external:onlyproject' (1 part), 'external:a:b:extra' (SplitN caps at 3 but a 4-segment ref still yields unexpected capability content — actually 4 segments split to 3 with capability 'b:extra', but a ref like 'external:a:b:c:d' intent mismatch), or 'external:' with empty remainder.

Common situations: Capability names containing colons; omitting the capability segment; copying a ref from docs and dropping a segment; embedding URLs (which contain '://') as the project/capability.

Related errors


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