{"record":{"id":"18572442082d13e9","repo":"JuliusBrussee/caveman","slug":"compat-route-q-does-not-match-default-compat-mo","errorCode":null,"errorMessage":"compat route %q does not match default /compat/ mount","messagePattern":"compat route %q does not match default /compat/ mount","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/providers/openaicompat/openaicompat.go","lineNumber":46,"sourceCode":"// keeps direct adapter users fail-closed as well.\nfunc (a Adapter) MatchRoute(method, path string) bool {\n\tif err := validateCompatPath(path, \"\"); err != nil {\n\t\treturn false\n\t}\n\treturn a.Base.MatchRoute(method, path)\n}\n\n// ResolveUpstreamURL removes only the default public /compat mount before\n// resolving the provider path. Named adapters and the reserved legacy routes\n// keep their dedicated resolver/compatibility behavior; this method exists for\n// the bare providers.openai_compatible route only.\nfunc (a Adapter) ResolveUpstreamURL(_ context.Context, req *http.Request, route providers.RouteContext) (*url.URL, error) {\n\tif req == nil || req.URL == nil || !strings.HasPrefix(req.URL.Path, \"/compat/\") {\n\t\tpath := \"\"\n\t\tif req != nil && req.URL != nil {\n\t\t\tpath = req.URL.Path\n\t\t}\n\t\treturn nil, fmt.Errorf(\"compat route %q does not match default /compat/ mount\", path)\n\t}\n\tif err := validateCompatPath(req.URL.Path, req.URL.RawPath); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// /compat/stub and /compat/openai-compatible were the original default\n\t// routes. They share the same strict path and query handling as the bare\n\t// mount, but retain their historical prefix stripping.\n\trequestPath := strings.TrimPrefix(req.URL.Path, \"/compat\")\n\tfor _, legacy := range []string{\"/stub\", \"/openai-compatible\"} {\n\t\tif hasCompatPrefix(req.URL.Path, \"/compat\"+legacy) {\n\t\t\trequestPath = strings.TrimPrefix(req.URL.Path, \"/compat\"+legacy)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tbaseURL := a.Base.BaseURL\n\tif route.BaseURL != \"\" {","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/providers/openaicompat/openaicompat.go#L28-L64","documentation":"The openaicompat adapter only serves requests mounted under the /compat/ path prefix; ResolveUpstreamURL rejects any request whose URL path does not start with /compat/. The error reports the offending path so you can see which route was misrouted to the compat provider.","triggerScenarios":"An http.Request whose URL.Path lacks the /compat/ prefix (or a nil request/URL) reaches the compat adapter's ResolveUpstreamURL during route resolution.","commonSituations":"Mounting the openai_compatible adapter on a custom route prefix other than /compat/; a reverse-proxy rewrite strips /compat/ before the request hits the provider; programmatic adapter use invoking ResolveUpstreamURL directly with a raw path.","solutions":["Route the request through a path beginning with /compat/ (e.g. /compat/<mount-name>/v1/...).","If you need a custom prefix, use the named-mount mechanism (NewNamedWithWireDialect / config named mounts) instead of relying on the default mount.","Check any rewriting middleware (ingress, strip-prefix) is not removing the /compat/ segment.","Verify the route is being dispatched to the correct adapter, not the compat one, if the path is intentionally non-compat."],"exampleFix":"// before\nhttp.Post(\"http://proxy/v1/chat/completions\", ...)\n// after\nhttp.Post(\"http://proxy/compat/openai-compatible/v1/chat/completions\", ...)","handlingStrategy":"validation","validationCode":"func isCompatRoute(u *url.URL) bool {\n    return u != nil && strings.HasPrefix(u.Path, \"/compat/\")\n}","typeGuard":null,"tryCatchPattern":"upstream, err := adapter.ResolveUpstreamURL(ctx, req, routeCtx)\nif err != nil && strings.Contains(err.Error(), \"does not match default /compat/ mount\") {\n    return fmt.Errorf(\"rewrite request to /compat/<mount>/... before dispatch: %w\", err)\n}","preventionTips":["Always build compat client URLs as /compat/<mount-name>/v1/...","Audit ingress/rewrite rules for prefix stripping of /compat/.","Use the proxy's client SDK/connector instead of hand-assembled paths."],"tags":["go","proxy","routing","url-path"],"backgroundTag":"invalid-url-format","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"}