gastownhall/beads · error

unknown dependency type %q; valid types: %s

Error message

unknown dependency type %q; valid types: %s

What it means

The second validateDependencyType branch: the type string is well-formed (non-empty, within length) but not in WellKnownDependencyTypes (blocks, parent-child, conditional-blocks, waits-for, related, discovered-from, ...). `bd create --deps` and `bd dep add` deliberately reject custom dependency types so both commands stay in lockstep; the error lists the valid set.

Source

Thrown at cmd/bd/create_deps.go:189

		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)")
		}
		return nil, nil
	}
	if gate == "" {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Replace the type with one from the printed valid list (blocks, parent-child, conditional-blocks, waits-for, related, discovered-from)
  2. Use "blocked-by"/"depends-on" aliases if you meant gating semantics — they map to blocks
  3. If you truly need a custom relation, model it as a related edge plus a label, or via an external reference

Example fix

// before
bd dep add bd-1 --type duplicates --target bd-2
// after
bd dep add bd-1 --type related --target bd-2
Defensive patterns

Strategy: validation

Validate before calling

var wellKnown = map[string]bool{
  "blocks":true, "parent-child":true, "conditional-blocks":true,
  "waits-for":true, "related":true, "discovered-from":true,
}
if !wellKnown[strings.TrimSpace(depType)] {
    return fmt.Errorf("type %q not accepted by bd; use a built-in", depType)
}

Prevention

When it happens

Trigger: `bd create ... --deps "requires:bd-5"` or `bd dep add bd-1 --type finish-to-start --target bd-2` — any plausible-sounding but non-built-in type, from parseDepSpec, readBulkDepEdges (bulk files), or runDepAddProxiedServer.

Common situations: Users porting habits from other trackers (e.g. "requires", "duplicates", "finish-to-start"); bulk dep files written for an older beads version that allowed custom types; typos like "parent" instead of "parent-child".

Related errors


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