JuliusBrussee/caveman · error

compat upstream

Error message

compat upstream %q: %w

What it means

NewNamedWithWireDialect wraps ValidateWireDialect failures with the offending mount name: "compat upstream %q: %w". It is raised when creating a named compat mount whose wire_dialect is neither "anthropic" nor empty, so startup or the test harness cannot construct the adapter.

Solutions

  1. Correct the wire_dialect for the named mount to "anthropic" or drop it (empty = OpenAI shape).
  2. The wrapped message names the mount (name in %q) — fix that mount's entry in config.
  3. If constructing programmatically, validate with providers.ValidateWireDialect (or openaicompat.ValidateWireDialect) before calling NewNamedWithWireDialect.
  4. Run the config validation (validateCompat path) at startup to catch this before serving traffic.

Example fix

// before
adapter, err := openaicompat.NewNamedWithWireDialect("claude", url, "openai-shape")
// after
adapter, err := openaicompat.NewNamedWithWireDialect("claude", url, "anthropic")
Defensive patterns

Strategy: validation

Validate before calling

if d := mount.WireDialect; d != "" && d != "anthropic" {
    return fmt.Errorf("mount %q: wire_dialect %q not supported", mount.Name, d)
}

Try / catch

adapter, err := openaicompat.NewNamedWithWireDialect(name, baseURL, dialect)
if err != nil {
    return nil, fmt.Errorf("constructing compat mount: %w", err)
}

Prevention

When it happens

Trigger: Calling NewNamedWithWireDialect(name, baseURL, dialect, ...) or buildAdapters on config with an invalid dialect string; also exercised by the dialect stream/non-stream tests that pass an unknown dialect.

Common situations: Invalid wire_dialect in the mounts config loaded at startup; unit/integration tests constructing mounts with an intentionally bad dialect; config templating injecting a dialect variable that is empty-but-nonstandard (e.g. "none").

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


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

Appendix: source

Thrown at proxy/providers/openaicompat/openaicompat.go:374

// 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.
//
// Routing, header mapping, telemetry provider, and pricing keep the mount's
// openai_compatible identity in every dialect.
func NewNamedWithWireDialect(name, baseURL, wireDialect string, forwardHeaders ...string) (providers.Adapter, error) {
	if err := ValidateName(name); err != nil {
		return nil, err
	}
	if err := ValidateWireDialect(wireDialect); err != nil {
		return nil, fmt.Errorf("compat upstream %q: %w", name, err)
	}
	baseURL = strings.TrimSpace(baseURL)
	if err := ValidateBaseURL(baseURL); err != nil {
		return nil, fmt.Errorf("compat upstream %q base_url: %w", name, err)
	}
	if err := ValidateForwardHeaders(forwardHeaders); err != nil {
		return nil, fmt.Errorf("compat upstream %q forward_headers: %w", name, err)
	}
	prefix := "/compat/" + name
	return namedAdapter{
		Base: providers.Base{
			Provider:      "openai_compatible",
			BaseURL:       baseURL,
			Routes:        []string{prefix + "/"},
			UsageProvider: wireDialectUsageProvider[wireDialect],
		},
		prefix:         prefix,
		forwardHeaders: append([]string(nil), forwardHeaders...),

View on GitHub (pinned to 3ee70a1026)