JuliusBrussee/caveman · error

rewriter: model is required

Error message

rewriter: model is required

What it means

rewriter.New validates its Config before constructing the client; Provider and Model are both mandatory. This error is returned when cfg.Model is empty or whitespace-only after trimming, because the rewriter cannot issue requests without a model identifier.

Solutions

  1. Set cfg.Model to a valid model identifier (e.g. "claude-sonnet-4-5" or "gpt-5") before calling New
  2. Check the config file/env var that feeds the rewriter Config for the missing model field
  3. Trim whitespace — a value of only spaces is treated as empty

Example fix

// before
rw, err := rewriter.New(rewriter.Config{Provider: "anthropic"})
// after
rw, err := rewriter.New(rewriter.Config{Provider: "anthropic", Model: "claude-sonnet-4-5"})
Defensive patterns

Strategy: validation

Validate before calling

func validateRewriterConfig(cfg rewriter.Config) error {
	if strings.TrimSpace(cfg.Provider) != "anthropic" && strings.TrimSpace(cfg.Provider) != "openai" {
		return fmt.Errorf("unsupported provider %q", cfg.Provider)
	}
	if strings.TrimSpace(cfg.Model) == "" {
		return errors.New("model required")
	}
	return nil
}

Try / catch

rw, err := rewriter.New(cfg)
if err != nil {
	return fmt.Errorf("rewriter init: %w", err)
}

Prevention

When it happens

Trigger: Calling rewriter.New with Config{Provider:"anthropic"|"openai", Model:""} — e.g. a struct literal built from config where the model field was never populated.

Common situations: YAML/JSON config missing a 'model' key, env var for the model unset, or a refactor that renamed the config field so the value lands elsewhere.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/589f1e35f02d5ebd. Report an issue: GitHub.

Appendix: source

Thrown at rewriter/rewriter.go:134

	InputTokens  int    // rewriter's own metered usage, for cost netting
	OutputTokens int
	// CandidateTokens is the inferred size of what the model produced, reported
	// on rejected calls so a corpus study can size the rewrites the gate threw
	// away. The bytes themselves never leave on a rejection.
	CandidateTokens int
}

// New validates cfg and returns a Client. An unknown provider is an error
// rather than a default: a silently mis-routed rewriter would produce bytes no
// gate was designed for.
func New(cfg Config) (*Client, error) {
	provider := strings.ToLower(strings.TrimSpace(cfg.Provider))
	if provider != providerAnthropic && provider != providerOpenAI {
		return nil, fmt.Errorf("rewriter: unsupported provider %q", cfg.Provider)
	}
	model := strings.TrimSpace(cfg.Model)
	if model == "" {
		return nil, errors.New("rewriter: model is required")
	}
	if strings.TrimSpace(cfg.APIKey) == "" {
		return nil, errors.New("rewriter: api key is required")
	}
	theta := cfg.Theta
	if theta == 0 {
		theta = DefaultTheta
	}
	if theta < 0 {
		return nil, fmt.Errorf("rewriter: theta must not be negative, got %d", theta)
	}
	doer := cfg.HTTPDoer
	if doer == nil {
		doer = http.DefaultClient.Do
	}
	return &Client{provider: provider, model: model, apiKey: cfg.APIKey, theta: theta, doer: doer}, nil
}

View on GitHub (pinned to 3ee70a1026)