{"record":{"id":"4a958d531d558389","repo":"astrid-runtime/astrid","slug":"github-releases-url-cannot-be-a-base","errorCode":null,"errorMessage":"GitHub releases URL cannot be a base","messagePattern":"GitHub releases URL cannot be a base","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/capsule/install_github.rs","lineNumber":42,"sourceCode":"                 (not a valid HTTP header value); proceeding with anonymous GitHub API access\"\n            ),\n        }\n    }\n    reqwest::Client::builder()\n        .user_agent(\"astrid-cli\")\n        .timeout(std::time::Duration::from_secs(30))\n        .default_headers(headers)\n        .build()\n        .context(\"failed to build GitHub HTTP client\")\n}\n\npub(super) fn release_tag_url(org: &str, repo: &str, tag: &str) -> anyhow::Result<String> {\n    let mut url = reqwest::Url::parse(&format!(\n        \"https://api.github.com/repos/{org}/{repo}/releases\"\n    ))\n    .context(\"failed to build GitHub releases URL\")?;\n    url.path_segments_mut()\n        .map_err(|()| anyhow::anyhow!(\"GitHub releases URL cannot be a base\"))?\n        .push(\"tags\")\n        .push(tag);\n    Ok(url.to_string())\n}\n\npub(super) async fn resolve_github_ref(\n    client: &reqwest::Client,\n    org: &str,\n    repo: &str,\n    version: Option<&str>,\n    tag: Option<&str>,\n) -> anyhow::Result<String> {\n    if let Some(tag) = tag {\n        return Ok(tag.to_string());\n    }\n    if let Some(version) = version {\n        for candidate in [format!(\"v{version}\"), version.to_string()] {\n            let tag_url = release_tag_url(org, repo, &candidate)?;","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/capsule/install_github.rs#L24-L60","documentation":"`release_tag_url` builds the GitHub API releases URL and then appends `tags/<tag>` via `Url::path_segments_mut`. That method returns `Err(())` when the URL cannot have path segments — a cannot-be-a-base URL — which should be impossible for the https URL constructed here, so this error indicates an internal invariant violation rather than user input.","triggerScenarios":"Practically unreachable: it fires only if `reqwest::Url::parse` produced a cannot-be-a-base URL for `https://api.github.com/repos/{org}/{repo}/releases`, or if the org/repo/tag strings contain characters that break parsing such that the parsed URL is opaque (e.g. embedded scheme/control characters via unsanitized input).","commonSituations":"Only seen if the surrounding code changes the base URL template, or if org/repo values interpolated into the URL contain malicious/odd characters that alter URL parsing.","solutions":["Verify org/repo/tag inputs are plain identifiers without `:`, `//`, or control characters","If you modified the base URL string, ensure it remains a special (http/https) URL so it has path segments","Update astrid-cli — as shipped this is an internal bug and worth reporting"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Ensure identifiers are URL-safe before calling:\nfn url_safe_id(s: &str) -> bool {\n    !s.is_empty() && s.chars().all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_' || c == '.')\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"cannot be a base\") => {\n        eprintln!(\"Internal URL construction bug; report org/repo values used.\");\n    }\n    other => other?,\n}","preventionTips":["Keep org/repo/tag values as plain URL-safe identifiers","Sanitize inputs interpolated into URL templates","Report occurrences upstream — as shipped this path should be unreachable"],"tags":["url","github","internal","api"],"backgroundTag":"invalid-url-format","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}