{"record":{"id":"f7e82d9008934d1c","repo":"gitbutlerapp/gitbutler","slug":"gitlabinvalidhost","errorCode":"GitLabInvalidHost","errorMessage":"'{host}' is not an absolute URL. Use the full URL of your GitLab instance, for example https://gitlab.example.com","messagePattern":"'(.+?)' is not an absolute URL\\. Use the full URL of your GitLab instance, for example https://gitlab\\.example\\.com","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-gitlab/src/client.rs","lineNumber":114,"sourceCode":"        );\n\n        let client = reqwest::Client::builder()\n            .default_headers(headers)\n            .timeout(GITLAB_REQUEST_TIMEOUT)\n            .build()?;\n\n        let base_url = if host.ends_with(\"/api/v4\") {\n            host.to_string()\n        } else if host.ends_with('/') {\n            format!(\"{host}api/v4\")\n        } else {\n            format!(\"{host}/api/v4\")\n        };\n        // reqwest rejects a URL without a scheme and host at request time with a\n        // generic builder error; check the same rule up front so the user is told\n        // what is wrong with the host they entered.\n        if !reqwest::Url::parse(&base_url).is_ok_and(|url| url.has_host()) {\n            return Err(anyhow::anyhow!(\n                but_error::Context::new(format!(\n                    \"'{host}' is not an absolute URL. Use the full URL of your GitLab instance, for example https://gitlab.example.com\"\n                ))\n                .with_code(but_error::Code::GitLabInvalidHost)\n            ));\n        }\n\n        Ok(Self { client, base_url })\n    }\n\n    pub async fn get_authenticated(&self) -> Result<AuthenticatedUser> {\n        #[derive(Deserialize)]\n        struct User {\n            username: String,\n            name: Option<String>,\n            email: Option<String>,\n            avatar_url: Option<String>,\n        }","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-gitlab/src/client.rs#L96-L132","documentation":"new_with_host_override validates the GitLab instance base URL up front: it must parse as an absolute URL with a host (scheme + host), because reqwest otherwise fails only at request time with a generic error. The host the user supplied is relative or malformed.","triggerScenarios":"Calling new_with_host_override with a host like `gitlab.example.com` (no scheme) or `localhost:8080/api` fragments that fail reqwest::Url::parse or yield a URL without a host.","commonSituations":"User entered the instance host without https:// in forge config; trailing path mistakes; copy-paste losing the scheme; assuming a bare hostname is accepted like some git CLIs do.","solutions":["Set the host to a full absolute URL, e.g. https://gitlab.example.com (scheme included)","If using a self-hosted instance on a custom port, include it: https://gitlab.example.com:8443","Fix the forge config value for the GitLab host and retry"],"exampleFix":"// before\nlet client = GitLabClient::new_with_host_override(storage, Some(\"gitlab.example.com\"))?;\n// after\nlet client = GitLabClient::new_with_host_override(storage, Some(\"https://gitlab.example.com\"))?;","handlingStrategy":"validation","validationCode":"fn is_absolute_url(host: &str) -> bool {\n    reqwest::Url::parse(host).map(|u| u.has_host()).unwrap_or(false)\n}\nif !is_absolute_url(host) { eprintln!(\"Use full URL like https://gitlab.example.com\"); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always store GitLab hosts with scheme (https://) in config","Validate host format at config-entry time, before client construction","Include port in the stored URL for self-hosted instances"],"tags":["gitlab","url","config"],"backgroundTag":"invalid-url-format","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}