charmbracelet/crush · error

failed to marshal schema: %w

Error message

failed to marshal schema: %w

What it means

The `crush schema` command reflects config.Config into a JSON schema and marshals it with json.MarshalIndent. MarshalIndent only fails if the reflected schema contains values JSON cannot encode (unsupported types, invalid maps, or a custom MarshalJSON returning an error), making this a rare internal invariant failure.

Source

Thrown at internal/cmd/schema.go:26

	"github.com/charmbracelet/crush/internal/agent/hyper"
	"github.com/charmbracelet/crush/internal/config"
	"github.com/charmbracelet/crush/internal/discover"
	"github.com/invopop/jsonschema"
	"github.com/spf13/cobra"
)

var schemaCmd = &cobra.Command{
	Use:    "schema",
	Short:  "Generate JSON schema for configuration",
	Long:   "Generate JSON schema for the crush configuration file",
	Hidden: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		reflector := new(jsonschema.Reflector)
		schema := reflector.Reflect(&config.Config{})
		setProviderTypeEnum(schema)
		bts, err := json.MarshalIndent(schema, "", "  ")
		if err != nil {
			return fmt.Errorf("failed to marshal schema: %w", err)
		}
		fmt.Println(string(bts))
		return nil
	},
}

// setProviderTypeEnum overwrites the provider `type` enum with the live set
// of accepted values rather than a hand-maintained struct tag. The values
// must match exactly what load.go validates against: the catwalk provider
// types, the Charm Hyper type, and any locally-discovered providers that
// self-register an enricher (e.g. ollama, omlx). Sourcing the enum here keeps
// the published schema from drifting as provider types are added or renamed.
func setProviderTypeEnum(schema *jsonschema.Schema) {
	def, ok := schema.Definitions["ProviderConfig"]
	if !ok || def.Properties == nil {
		return
	}
	typeProp, ok := def.Properties.Get("type")

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Rebuild/reinstall Crush to rule out a stale binary mismatched with the config package.
  2. Identify the offending field in internal/config/config.go and give it a JSON-safe representation or valid MarshalJSON.
  3. Upgrade to the latest Crush release where the schema generation bug may already be fixed.
  4. Report the bug with the stack trace since this should be unreachable in normal operation.

Example fix

// before
// config field with broken custom marshaller
func (p Provider) MarshalJSON() ([]byte, error) { return nil, errors.New("unsupported") }
// after
func (p Provider) MarshalJSON() ([]byte, error) { return json.Marshal(string(p)) }
Defensive patterns

Strategy: try-catch

Try / catch

bts, err := json.MarshalIndent(schema, "", "  ")
if err != nil {
    return fmt.Errorf("failed to marshal schema: %w", err) // inspect %w for the offending type
}

Prevention

When it happens

Trigger: Running `crush schema` where the jsonschema.Reflector output for config.Config contains a value json.Marshal cannot serialize — e.g. a config type with a MarshalJSON method returning an error, or an exotic field type added to config.Config.

Common situations: Encountered after code changes to config.Config (new field with an unsupported/custom serializer) rather than by end users; corrupted toolchain or plugin injection is essentially unheard of.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/d3c3a62e38c38f35. Report an issue: GitHub.