{"record":{"id":"279e84625a86aa12","repo":"zeroclaw-labs/zeroclaw","slug":"openaicompatiblebuilder-auth-style-is-required","errorCode":null,"errorMessage":"OpenAiCompatibleBuilder: auth_style() is required","messagePattern":"OpenAiCompatibleBuilder: auth_style\\(\\) is required","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/compatible.rs","lineNumber":558,"sourceCode":"\n    /// Finalize the builder into a ready provider. Every optional construction\n    /// value must be set on this builder; the returned provider has no\n    /// post-construction mutators.\n    ///\n    /// # Panics\n    /// Panics if [`Self::display_name`], [`Self::base_url`], or\n    /// [`Self::auth_style`] was not called — those three fields carry no\n    /// sensible default and every real call site sets them.\n    pub fn build(self) -> OpenAiCompatibleModelProvider {\n        let name = self\n            .name\n            .expect(\"OpenAiCompatibleBuilder: display_name() is required\");\n        let base_url = self\n            .base_url\n            .expect(\"OpenAiCompatibleBuilder: base_url() is required\");\n        let auth_style = self\n            .auth_style\n            .expect(\"OpenAiCompatibleBuilder: auth_style() is required\");\n        // Either merge preset can enable the shared merge behavior.\n        let merge_system_into_user =\n            self.merge_system_into_user || self.merge_system_into_user_preserve_native;\n        // Default `native_tool_calling` is `!merge_system_into_user_disable_native`,\n        // i.e. only the \"combined preset\" builder setter disables it. The\n        // explicit `without_native_tools()` override wins if present.\n        let native_tool_calling = self\n            .native_tool_calling_override\n            .unwrap_or(!self.merge_system_into_user);\n        // Read the PEM bytes now so later HTTP clients incur no per-request I/O.\n        // A read error is logged at WARN and TLS falls back to system roots —\n        // preserving the established warning-and-fallback semantics.\n        let tls_ca_cert_pem =\n            self.tls_ca_cert_path\n                .as_deref()\n                .and_then(|path| match std::fs::read(path) {\n                    Ok(bytes) => Some(bytes),\n                    Err(e) => {","sourceCodeStart":540,"sourceCodeEnd":576,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/compatible.rs#L540-L576","documentation":"OpenAiCompatibleBuilder.build() requires an auth style (how the API key is attached: e.g. Authorization bearer header vs query parameter) because there is no safe default across OpenAI-compatible endpoints. This expect() panic fires when .auth_style() was never called before .build().","triggerScenarios":"Building an OpenAiCompatibleModelProvider via builder().build(), http_client(), streaming_http_client(), or make_model_provider() without calling .auth_style(AuthStyle::...) beforehand. Also when base_url was fixed (error 1520) but the auth-style setter was still omitted.","commonSituations":"Porting a provider preset that used a different auth convention; new integrations where the author set the key but not how it is transmitted; refactoring that drops the auth_style call while fixing a base_url panic.","solutions":["Call .auth_style(...) matching the provider (bearer-header for most OpenAI-compatible APIs) before .build().","Check how sibling provider presets in crates/zeroclaw-providers set auth_style and copy the convention.","Validate the whole builder contract (display_name + base_url + auth_style) in one place before build so all missing fields are reported together."],"exampleFix":"// before\nlet provider = OpenAiCompatibleModelProvider::builder()\n    .display_name(\"my-llm\")\n    .base_url(url)\n    .build(); // panics: auth_style() is required\n\n// after\nlet provider = OpenAiCompatibleModelProvider::builder()\n    .display_name(\"my-llm\")\n    .base_url(url)\n    .auth_style(AuthStyle::Bearer)\n    .build();","handlingStrategy":"validation","validationCode":"// Decide the auth style from config before building:\nlet auth_style = match config.auth_style.as_deref() {\n    Some(\"bearer\") => AuthStyle::Bearer,\n    Some(\"query\") => AuthStyle::QueryParam,\n    other => return Err(anyhow::anyhow!(\"unsupported auth_style: {other:?}\")),\n};\nlet provider = OpenAiCompatibleModelProvider::builder()\n    .display_name(name)\n    .base_url(base_url)\n    .auth_style(auth_style)\n    .build();","typeGuard":null,"tryCatchPattern":"let provider = std::panic::catch_unwind(|| builder.build())\n    .map_err(|_| anyhow::anyhow!(\"provider builder contract violated: auth_style required\"))?;","preventionTips":["Never call .build() on OpenAiCompatibleBuilder without all three required setters in the same expression chain.","Mirror the auth-style convention of existing presets in crates/zeroclaw-providers when adding providers.","Fail fast on unknown auth-style config values instead of skipping the setter."],"tags":["rust","builder","panic","provider","authentication"],"backgroundTag":"builder-missing-required-field","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}