gastownhall/beads · error

invalid format '%s', expected 'variable=value' or 'value=var

Error message

invalid format '%s', expected 'variable=value' or 'value=variable'

What it means

`parseDistillVar` parses `bd mol distill --var` flags, which must contain exactly one `=` with non-empty text on both sides. The flag supports two syntaxes: spawn-style `variable=value` and substitution-style `value=variable`. A flag without `=`, or with an empty side (e.g. `=foo` or `bar=`), is structurally invalid and rejected before any text lookup happens.

Source

Thrown at cmd/bd/mol_distill.go:80

func collectSubgraphText(subgraph *MoleculeSubgraph) string {
	var parts []string
	for _, issue := range subgraph.Issues {
		parts = append(parts, issue.Title)
		parts = append(parts, issue.Description)
		parts = append(parts, issue.Design)
		parts = append(parts, issue.AcceptanceCriteria)
		parts = append(parts, issue.Notes)
	}
	return strings.Join(parts, " ")
}

// parseDistillVar parses a --var flag with smart detection of syntax.
// Accepts both spawn-style (variable=value) and substitution-style (value=variable).
// Returns (findText, varName, error).
func parseDistillVar(varFlag, searchableText string) (string, string, error) {
	parts := strings.SplitN(varFlag, "=", 2)
	if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
		return "", "", fmt.Errorf("invalid format '%s', expected 'variable=value' or 'value=variable'", varFlag)
	}

	left, right := parts[0], parts[1]
	leftFound := strings.Contains(searchableText, left)
	rightFound := strings.Contains(searchableText, right)

	switch {
	case rightFound && !leftFound:
		// spawn-style: --var branch=feature-auth
		// left is variable name, right is the value to find
		return right, left, nil
	case leftFound && !rightFound:
		// substitution-style: --var feature-auth=branch
		// left is value to find, right is variable name
		return left, right, nil
	case leftFound && rightFound:
		// Both found - prefer spawn-style (more natural guess)
		// Agent likely typed: --var varname=concrete_value

View on GitHub (pinned to 71377f2769)

Solutions

  1. Use the documented `variable=value` form, e.g. `--var epic_name=auth-refactor`.
  2. Check for shell quoting issues: quote the whole flag (`--var 'name=value'`) if the value contains spaces.
  3. If you intended substitution-style, ensure both sides are non-empty, e.g. `--var 'auth-refactor=epic_name'`.

Example fix

// before
bd mol distill --epic bd-42 --var epic_name
// after
bd mol distill --epic bd-42 --var epic_name=auth-refactor
Defensive patterns

Strategy: validation

Validate before calling

// shell: validate --var shape before invoking bd
VAR='epic_name=auth-refactor'
case "$VAR" in
  *=*) L=${VAR%%=*}; R=${VAR#*=}
       [[ -n "$L" && -n "$R" ]] || { echo "--var needs non-empty variable and value"; exit 1; } ;;
  *)   echo "--var must be variable=value"; exit 1 ;;
esac
bd mol distill --epic bd-42 --var "$VAR"

Type guard

func validVarFlag(f string) bool {
	p := strings.SplitN(f, "=", 2)
	return len(p) == 2 && p[0] != "" && p[1] != ""
}

Try / catch

if err := runDistill(); err != nil && strings.Contains(err.Error(), "invalid format") {
	fmt.Fprintln(os.Stderr, "usage: --var variable=value or value=variable")
}

Prevention

When it happens

Trigger: Running `bd mol distill --var foo` (no `=`), `--var =foo`, or `--var foo=` from `distillSubgraph` or the proxied-server path. The `strings.SplitN(varFlag, "=", 2)` result has length != 2 or an empty part, hitting the `len(parts) != 2 || parts[0] == "" || parts[1] == ""` branch.

Common situations: Quoting mistakes in shell that drop the `=`; forgetting the variable name when only supplying a value; typos like double `==` handled by SplitN into an empty part; copying flags from docs that used placeholder syntax.

Related errors


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