gastownhall/beads · error

config storage-class.%s: %w

Error message

config storage-class.%s: %w

What it means

resolveStorageClass validates the storage-class value after deciding its source: an explicit --storage-class flag failure is returned bare (a usage error), but when the value came from per-type config (storage-class.<type>) and ParseStorageClass rejects it, the error is wrapped with the config key. This makes a bad config value identifiable as a configuration bug rather than a command-line mistake, and it fails loudly per Protocol v0.1 C1.3.

Source

Thrown at cmd/bd/create.go:731

// The parsed class is returned verbatim, including versioned. The caller must
// normalize versioned to the unset marker (the marker is omitted when
// versioned, C2.4) only AFTER plane-conflict validation, so an explicit durable
// request paired with a wisp-plane flag is rejected rather than silently erased
// into an effective-ephemeral row. Values are validated wherever they came
// from: a bad flag is a usage error, a bad config value is a config bug and
// fails just as loudly.
func resolveStorageClass(explicit string, issueType types.IssueType) (types.StorageClass, error) {
	raw := explicit
	if raw == "" {
		raw = config.GetString("storage-class." + string(issueType))
		if raw == "" {
			return "", nil
		}
	}
	class, err := types.ParseStorageClass(raw)
	if err != nil {
		if explicit == "" {
			return "", fmt.Errorf("config storage-class.%s: %w", issueType, err)
		}
		return "", err
	}
	return class, nil
}

// reconcileStorageClassPlane applies flag-over-config precedence between a
// resolved storage class and the effective wisp plane (Protocol v0.1 §C1.3).
// A wisp-plane record is ephemeral by construction, so a durable class
// (versioned/unversioned) cannot ride on it. explicit reports whether the class
// came from an explicit flag/field rather than a per-type config default:
//   - explicit durable class + wisp plane -> conflict=true; the caller rejects
//     it so the durable intent is preserved rather than silently collapsed into
//     an effective-ephemeral record;
//   - config-derived durable class + wisp plane -> cleared, yielding to the
//     explicit --ephemeral/--no-history plane.
//
// versioned normalizes to the unset marker (C2.4) only after the check, so the

View on GitHub (pinned to 71377f2769)

Solutions

  1. Fix the config value for storage-class.<type> to a valid storage class (e.g. versioned/unversioned/ephemeral as accepted by types.ParseStorageClass)
  2. Run with an explicit --storage-class <valid> flag to override the bad config and unblock the create
  3. Print the effective config (`bd config` / config get storage-class.<type>) to confirm which key/value is being read
  4. Align with your team's config template and bd version — older or newer versions may accept different tokens

Example fix

# before (config)
storage-class.bug: durable-ish
# after
storage-class.bug: versioned
Defensive patterns

Strategy: validation

Validate before calling

// Validate the config value before running bd create
raw := config.GetString("storage-class." + issueType)
if raw != "" {
    if _, err := types.ParseStorageClass(raw); err != nil {
        return fmt.Errorf("storage-class.%s is invalid: %w", issueType, err)
    }
}

Try / catch

sc, err := resolveStorageClass(explicit, issueType)
if err != nil {
    if strings.HasPrefix(err.Error(), "config storage-class.") {
        // bad config value: fix config, not the CLI flags
    }
    return err // bare error means bad --storage-class flag (usage error)
}

Prevention

When it happens

Trigger: Creating an issue without --storage-class while config key storage-class.<issueType> (e.g. storage-class.bug in beads config or a config file) holds a value types.ParseStorageClass doesn't accept — misspelled class names, wrong case, or an unsupported token.

Common situations: Hand-edited config files with `storage-class.bug: durable-ish`; copied configs from docs of a different version; typos like `vesioned` instead of `versioned`; config applied to a type whose key was spelled wrong.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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