gitbutlerapp/gitbutler · error

GitLabInvalidHost

GitLabInvalidHost

Error message

'{host}' is not an absolute URL. Use the full URL of your GitLab instance, for example https://gitlab.example.com

What it means

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.

Solutions

  1. Set the host to a full absolute URL, e.g. https://gitlab.example.com (scheme included)
  2. If using a self-hosted instance on a custom port, include it: https://gitlab.example.com:8443
  3. Fix the forge config value for the GitLab host and retry

Example fix

// before
let client = GitLabClient::new_with_host_override(storage, Some("gitlab.example.com"))?;
// after
let client = GitLabClient::new_with_host_override(storage, Some("https://gitlab.example.com"))?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_absolute_url(host: &str) -> bool {
    reqwest::Url::parse(host).map(|u| u.has_host()).unwrap_or(false)
}
if !is_absolute_url(host) { eprintln!("Use full URL like https://gitlab.example.com"); }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/f7e82d9008934d1c. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-gitlab/src/client.rs:114

        );

        let client = reqwest::Client::builder()
            .default_headers(headers)
            .timeout(GITLAB_REQUEST_TIMEOUT)
            .build()?;

        let base_url = if host.ends_with("/api/v4") {
            host.to_string()
        } else if host.ends_with('/') {
            format!("{host}api/v4")
        } else {
            format!("{host}/api/v4")
        };
        // reqwest rejects a URL without a scheme and host at request time with a
        // generic builder error; check the same rule up front so the user is told
        // what is wrong with the host they entered.
        if !reqwest::Url::parse(&base_url).is_ok_and(|url| url.has_host()) {
            return Err(anyhow::anyhow!(
                but_error::Context::new(format!(
                    "'{host}' is not an absolute URL. Use the full URL of your GitLab instance, for example https://gitlab.example.com"
                ))
                .with_code(but_error::Code::GitLabInvalidHost)
            ));
        }

        Ok(Self { client, base_url })
    }

    pub async fn get_authenticated(&self) -> Result<AuthenticatedUser> {
        #[derive(Deserialize)]
        struct User {
            username: String,
            name: Option<String>,
            email: Option<String>,
            avatar_url: Option<String>,
        }

View on GitHub (pinned to 58e5313667)