{"record":{"id":"589f1e35f02d5ebd","repo":"JuliusBrussee/caveman","slug":"rewriter-model-is-required","errorCode":null,"errorMessage":"rewriter: model is required","messagePattern":"rewriter: model is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rewriter/rewriter.go","lineNumber":134,"sourceCode":"\tInputTokens  int    // rewriter's own metered usage, for cost netting\n\tOutputTokens int\n\t// CandidateTokens is the inferred size of what the model produced, reported\n\t// on rejected calls so a corpus study can size the rewrites the gate threw\n\t// away. The bytes themselves never leave on a rejection.\n\tCandidateTokens int\n}\n\n// New validates cfg and returns a Client. An unknown provider is an error\n// rather than a default: a silently mis-routed rewriter would produce bytes no\n// gate was designed for.\nfunc New(cfg Config) (*Client, error) {\n\tprovider := strings.ToLower(strings.TrimSpace(cfg.Provider))\n\tif provider != providerAnthropic && provider != providerOpenAI {\n\t\treturn nil, fmt.Errorf(\"rewriter: unsupported provider %q\", cfg.Provider)\n\t}\n\tmodel := strings.TrimSpace(cfg.Model)\n\tif model == \"\" {\n\t\treturn nil, errors.New(\"rewriter: model is required\")\n\t}\n\tif strings.TrimSpace(cfg.APIKey) == \"\" {\n\t\treturn nil, errors.New(\"rewriter: api key is required\")\n\t}\n\ttheta := cfg.Theta\n\tif theta == 0 {\n\t\ttheta = DefaultTheta\n\t}\n\tif theta < 0 {\n\t\treturn nil, fmt.Errorf(\"rewriter: theta must not be negative, got %d\", theta)\n\t}\n\tdoer := cfg.HTTPDoer\n\tif doer == nil {\n\t\tdoer = http.DefaultClient.Do\n\t}\n\treturn &Client{provider: provider, model: model, apiKey: cfg.APIKey, theta: theta, doer: doer}, nil\n}\n","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/rewriter/rewriter.go#L116-L152","documentation":"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.","triggerScenarios":"Calling rewriter.New with Config{Provider:\"anthropic\"|\"openai\", Model:\"\"} — e.g. a struct literal built from config where the model field was never populated.","commonSituations":"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.","solutions":["Set cfg.Model to a valid model identifier (e.g. \"claude-sonnet-4-5\" or \"gpt-5\") before calling New","Check the config file/env var that feeds the rewriter Config for the missing model field","Trim whitespace — a value of only spaces is treated as empty"],"exampleFix":"// before\nrw, err := rewriter.New(rewriter.Config{Provider: \"anthropic\"})\n// after\nrw, err := rewriter.New(rewriter.Config{Provider: \"anthropic\", Model: \"claude-sonnet-4-5\"})\n","handlingStrategy":"validation","validationCode":"func validateRewriterConfig(cfg rewriter.Config) error {\n\tif strings.TrimSpace(cfg.Provider) != \"anthropic\" && strings.TrimSpace(cfg.Provider) != \"openai\" {\n\t\treturn fmt.Errorf(\"unsupported provider %q\", cfg.Provider)\n\t}\n\tif strings.TrimSpace(cfg.Model) == \"\" {\n\t\treturn errors.New(\"model required\")\n\t}\n\treturn nil\n}\n","typeGuard":null,"tryCatchPattern":"rw, err := rewriter.New(cfg)\nif err != nil {\n\treturn fmt.Errorf(\"rewriter init: %w\", err)\n}\n","preventionTips":["Load the model field from config with a non-empty check at startup","Keep config struct field names stable across refactors","Fail fast on empty provider/model/api-key trio"],"tags":["rewriter","validation","missing-field"],"backgroundTag":"missing-required-config-field","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}