JuliusBrussee/caveman · error
wire dialect must be "anthropic" or empty
Error message
wire dialect %q must be "anthropic" or empty
What it means
ValidateWireDialect rejects wire_dialect values the named compat mount cannot honor. Only "anthropic" or an empty string (default OpenAI shape) are accepted; anything else would cause the mount to parse an upstream's responses with the wrong wire grammar. Exported so the config loader fails at startup (issue #1026: Anthropic-dialect upstream silently misclassified).
Solutions
- Set wire_dialect to "anthropic" if the upstream speaks the Anthropic Messages API, or remove the key entirely for OpenAI-shaped upstreams.
- Fix casing/spelling exactly: lowercase "anthropic".
- Remove the wire_dialect line if the upstream is OpenAI-compatible and no override is needed.
- Check the proxy docs/version for the accepted dialect list — only "anthropic" and empty are valid.
Example fix
# before [[compat_mount]] name = "claude" wire_dialect = "Anthropic" # after [[compat_mount]] name = "claude" wire_dialect = "anthropic"
Defensive patterns
Strategy: validation
Validate before calling
valid := dialect == "" || dialect == "anthropic"
if !valid {
return fmt.Errorf("unsupported wire_dialect %q; use \"anthropic\" or omit", dialect)
} Try / catch
if err := openaicompat.ValidateWireDialect(cfg.WireDialect); err != nil {
log.Fatalf("mount %s: %v", cfg.Name, err)
} Prevention
- Only ever write wire_dialect = "anthropic" or omit the key.
- Lowercase dialect values exactly as documented.
- Run the config loader's validation before deploying.
When it happens
Trigger: Config sets wire_dialect to a value not present in wireDialectUsageProvider — e.g. wire_dialect = "openai", "gemini", "Ollama", or a typo like "anthropic " — and validateCompat or NewNamedWithWireDialect calls ValidateWireDialect.
Common situations: Typo or casing mistake in config wire_dialect; copying a mount config that used a dialect name from another proxy; assuming other wire grammars are supported when only anthropic is.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- compat upstream name
- CAVEMAN_CCR_MAX_BYTES must be a positive integer
- ccr max storage bytes must be positive
- compat upstream name
- compat upstream base_url
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/e9b1fb4e11b7f3c0.
Report an issue: GitHub.
Appendix: source
Thrown at proxy/providers/openaicompat/openaicompat.go:348
// usage/cost telemetry keeps using the shared OpenAI-shape parser.
func NewNamed(name, baseURL string, forwardHeaders ...string) (providers.Adapter, error) {
return NewNamedWithWireDialect(name, baseURL, "", forwardHeaders...)
}
// wireDialectUsageProvider maps a configured wire dialect to the provider whose
// usage parser implements it. "" is the default OpenAI-shape parser.
var wireDialectUsageProvider = map[string]string{
"": "",
"anthropic": "anthropic",
}
// ValidateWireDialect rejects dialect values no named mount can honor. It is
// exported so the config loader fails at startup rather than silently parsing
// an Anthropic-dialect upstream with the OpenAI-shape rules — the exact
// misclassification issue #1026 reports.
func ValidateWireDialect(dialect string) error {
if _, ok := wireDialectUsageProvider[dialect]; !ok {
return fmt.Errorf("wire dialect %q must be \"anthropic\" or empty", dialect)
}
return nil
}
// NewNamedWithWireDialect builds a named mount whose upstream speaks a
// different wire grammar than the mount's OpenAI-compatible identity.
// "anthropic" is for an upstream that answers the Anthropic Messages protocol
// on the mount. It changes two things and nothing else:
//
// - USAGE ACCOUNTING parses with the Anthropic dialect (Base.UsageProvider):
// the usage block reports input_tokens EXCLUSIVE of cache reads/writes, so
// the OpenAI-shape contradiction check reads a warm cache as malformed and
// drops every such row from token accounting (issue #1026).
// - COMPRESSION ZONES follow the Anthropic Messages grammar on Messages-path
// requests and keep the OpenAI grammar on every other path (see
// anthropicWireZones): the Anthropic extractor keys the live/frozen
// boundary on the request's own cache_control breakpoints.
//View on GitHub (pinned to 3ee70a1026)