gastownhall/beads · error

cli version must not be empty

Error message

cli version must not be empty

What it means

ValidateReconcileVersion refuses an empty or whitespace-only cliVersion. Recording "" over a real marker would silently break the downgrade guard, and the empty marker it leaves behind is indistinguishable from a workspace nothing has ever reconciled. The only rule at this end is that a version has to name something.

Source

Thrown at internal/workapi/versionreconcile.go:60

	// together: a workspace catching up to a mark a newer binary already left
	// moves the marker to the mark and leaves the mark where it is.
	RecordHighWaterMark bool
}

// ValidateReconcileVersion checks the version a caller wants to record, and
// returns it unchanged.
//
// It is separate from the planner so a body can refuse BEFORE it reads anything
// or opens a unit of work. This runs on every startup, so a refusal that costs
// a round trip is a refusal that costs every command.
//
// The only rule at this end is that a version has to name something. Recording
// "" over a real marker would silently take the downgrade guard down with it,
// and the empty marker it left behind is indistinguishable from a workspace
// nothing has ever reconciled.
func ValidateReconcileVersion(cliVersion string) (string, error) {
	if strings.TrimSpace(cliVersion) == "" {
		return "", fmt.Errorf("%w: cli version must not be empty", issueops.ErrValidation)
	}
	return cliVersion, nil
}

// PlanVersionReconcile decides what recording cliVersion should do to a
// workspace whose markers currently read recorded and highWaterMark.
//
// The order of the checks is the contract, not an implementation detail. An
// exact match short-circuits first, so the steady-state path — every startup
// that is not the first one after an upgrade — decides without consulting the
// mark at all. Both downgrade guards then run BEFORE any write is planned, so
// a refusal is a decision rather than a write that is undone.
func PlanVersionReconcile(cliVersion, recorded, highWaterMark string) (VersionReconcilePlan, error) {
	if _, err := ValidateReconcileVersion(cliVersion); err != nil {
		return VersionReconcilePlan{}, err
	}

	if recorded == cliVersion {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Set cliVersion to the actual binary/build version string before calling PlanVersionReconcile
  2. Fix the build pipeline so the version ldflag is injected (e.g. -X main.version=...)
  3. Handle errors.Is(err, issueops.ErrValidation) and fail fast with 'cli version must not be empty'

Example fix

// before
plan, err := workapi.PlanVersionReconcile(version) // version == ""
// after
if strings.TrimSpace(version) == "" {
    return fmt.Errorf("refusing reconcile: binary built without a version")
}
plan, err := workapi.PlanVersionReconcile(version)
Defensive patterns

Strategy: validation

Validate before calling

if strings.TrimSpace(cliVersion) == "" {
    return fmt.Errorf("cli version must not be empty before reconcile")
}

Type guard

func hasVersion(v string) bool {
    return strings.TrimSpace(v) != ""
}

Try / catch

plan, err := workapi.PlanVersionReconcile(cliVersion)
if err != nil {
    if errors.Is(err, issueops.ErrValidation) {
        return fmt.Errorf("cannot reconcile: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling workapi.ValidateReconcileVersion("") directly, or calling PlanVersionReconcile, which invokes it, with a version string that is empty or whitespace.

Common situations: A build-time ldflags version variable was not injected (binary built without the version flag); a caller read the version from an unset env/config value; a test harness forgot to set the version before planning the reconcile.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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