gastownhall/beads · error

unsupported value %T for update field %q

Error message

unsupported value %T for update field %q

What it means

buildUpdatePatch (cmd/bd/update.go) recognizes a field key but the supplied value has the wrong Go type (the type assertion like value.(bool) fails), so the field is marked not-ok and this error reports the offending %T and field name. It fires when programmatic callers (or proxied JSON payloads decoded into interface{}) pass, say, a string where a bool or int is required.

Source

Thrown at cmd/bd/update.go:754

				patch.Metadata.Set = set
			}
		case storageissueops.OpUnsetMetadata:
			patch.Metadata.Unset, ok = value.([]string)
		case "wisp":
			var flag bool
			if flag, ok = value.(bool); ok {
				wisp = &flag
			}
		case "no_history":
			var flag bool
			if flag, ok = value.(bool); ok {
				noHistory = &flag
			}
		default:
			return issueops.IssuePatch{}, fmt.Errorf("unsupported update field %q", key)
		}
		if !ok {
			return issueops.IssuePatch{}, fmt.Errorf("unsupported value %T for update field %q", value, key)
		}
	}
	// --ephemeral/--persistent/--no-history/--history select one complete
	// persistence state. The flag parsing already rejects the contradictory
	// pairs; the remaining combinations resolve most-specific-first, which
	// reproduces the column pairs the old two-boolean write produced.
	switch {
	case wisp != nil && *wisp:
		patch.Persistence = setField(issueops.PersistenceModeEphemeral)
	case noHistory != nil && *noHistory:
		patch.Persistence = setField(issueops.PersistenceModeNoHistory)
	case wisp != nil || noHistory != nil:
		patch.Persistence = setField(issueops.PersistenceModePersistent)
	}
	return patch, nil
}

func stringField(value any) (issueops.Field[string], bool) {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Send the value with the expected type: true/false (not "true") for boolean fields like no_history, numbers unquoted for numeric fields
  2. Fix the client script to build the payload with native types (e.g. use jq --argjson or language-native JSON encoders)
  3. Check buildUpdatePatch's switch for the exact expected Go type per field and cast/convert before calling
  4. If a type legitimately changed between versions, update the proxy/client to the matching bd version

Example fix

// before
payload := `{"no_history": "true"}`
// after
payload := `{"no_history": true}`
Defensive patterns

Strategy: type-guard

Validate before calling

func checkValueTypes(fields map[string]any) error {
	for k, v := range fields {
		switch k {
		case "no_history", "ephemeral", "persistent":
			if _, ok := v.(bool); !ok {
				return fmt.Errorf("field %q must be bool, got %T", k, v)
			}
		}
	}
	return nil
}

Type guard

func asBool(v any) (bool, bool) {
	b, ok := v.(bool)
	return b, ok
}

Try / catch

patch, err := buildUpdatePatch(fields)
if err != nil {
	if strings.Contains(err.Error(), "unsupported value") {
		// coerce common string→native conversions and retry once
	}
	return err
}

Prevention

When it happens

Trigger: Sending {"no_history": "true"} (string) instead of true (bool) in an update payload; a scripting wrapper marshaling numbers as strings; a proxy client serializing enum-like values as strings where the switch expects a typed value.

Common situations: JSON APIs where values arrive as interface{} — JSON has no distinct bool/int typing guarantees if produced loosely; shell scripts building payloads with quoted values; version drift where a field's type changed.

Related errors


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