gastownhall/beads · error

invalid dependency type %q (must be non-empty, max %d chars)

Error message

invalid dependency type %q (must be non-empty, max %d chars); valid types: %s

What it means

validateDependencyType is the single shared gate used by `bd create --deps` and `bd dep add`: custom/unknown dependency types are intentionally rejected, only well-known built-ins are accepted. This first branch fires when the type fails basic IsValid() checks — empty, or longer than types.MaxDependencyTypeLen.

Source

Thrown at cmd/bd/create_deps.go:185

// like "parent-child" and custom types) passes through unchanged.
func canonicalDependencyType(t types.DependencyType) types.DependencyType {
	switch t {
	case "depends-on", "blocked-by":
		return types.DepBlocks
	default:
		return t
	}
}

// validateDependencyType enforces that a (post-alias-normalization)
// dependency type is both structurally valid and one of the well-known
// built-in types. `bd create --deps` and `bd dep add --type` intentionally
// reject custom/unknown dependency types (see the comment on
// WellKnownDependencyTypes) — this is the single shared check so both
// commands stay in lockstep.
func validateDependencyType(t types.DependencyType) error {
	if !t.IsValid() {
		return fmt.Errorf("invalid dependency type %q (must be non-empty, max %d chars); valid types: %s",
			t, types.MaxDependencyTypeLen, createDepsAcceptedTypeList())
	}
	if !t.IsWellKnown() {
		return fmt.Errorf("unknown dependency type %q; valid types: %s",
			t, createDepsAcceptedTypeList())
	}
	return nil
}

// buildWaitsFor validates and constructs a WaitsForSpec from the --waits-for
// and --waits-for-gate flag values. gateExplicit must be true when the caller
// explicitly passed --waits-for-gate (not relying on its default); in that case
// a missing spawnerID is rejected rather than silently ignored.
func buildWaitsFor(spawnerID, gate string, gateExplicit bool) (*domain.WaitsForSpec, error) {
	spawnerID = strings.TrimSpace(spawnerID)
	if spawnerID == "" {
		if gateExplicit {
			return nil, fmt.Errorf("--waits-for-gate requires --waits-for (no spawner ID specified)")

View on GitHub (pinned to 71377f2769)

Solutions

  1. Use one of the accepted built-in types listed in the error (blocks, parent-child, conditional-blocks, waits-for, related, discovered-from, etc.)
  2. Fix the empty/overlong type value in your bulk file or script variable
  3. Rely on the aliases "depends-on"/"blocked-by" which canonicalize to blocks

Example fix

// before
bd dep add bd-1 --type "super-long-custom-dependency-type-name-exceeding-limit" --target bd-2
// after
bd dep add bd-1 --type blocks --target bd-2
Defensive patterns

Strategy: validation

Validate before calling

if depType == "" || len(depType) > maxLen {
    return fmt.Errorf("dependency type empty or too long")
}

Prevention

When it happens

Trigger: `bd create ... --deps ":bd-5"` (empty type after canonicalization path), or a type string exceeding MaxDependencyTypeLen, via parseDepSpec, readBulkDepEdges, or runDepAddProxiedServer (`bd dep add --type "<very long string>"`).

Common situations: Bulk dependency files (bd dep add bulk) with a mangled first column leaving an empty type; generated scripts concatenating type names incorrectly and exceeding the length limit.

Related errors


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