{"record":{"id":"0a68b37ae6f7a0bf","repo":"gitbutlerapp/gitbutler","slug":"clone-remote-url-contains-unsupported-control-characters","errorCode":null,"errorMessage":"Clone remote URL contains unsupported control characters","messagePattern":"Clone remote URL contains unsupported control characters","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-debug/src/command/dump/repo_installer.rs","lineNumber":159,"sourceCode":"    let remote_url = remote\n        .url(gix::remote::Direction::Fetch)\n        .with_context(|| format!(\"Clone remote '{name}' has no fetch URL\"))?;\n    let mut url = remote_url\n        .to_bstring()\n        .to_str()\n        .context(\"Clone remote URL is not UTF-8\")?\n        .to_owned();\n    if remote_url.scheme == gix::url::Scheme::File\n        && remote_url.serialize_alternative_form\n        && Path::new(&url).is_relative()\n    {\n        url = workdir\n            .join(&url)\n            .to_str()\n            .context(\"Absolute clone remote path is not UTF-8\")?\n            .to_owned();\n    }\n    ensure!(\n        !url.contains(['\\n', '\\r', '\\0']),\n        \"Clone remote URL contains unsupported control characters\"\n    );\n    Ok(CloneRemote { name, url })\n}\n\nfn head(repo: &gix::Repository) -> Result<(String, Option<String>)> {\n    let head = repo.head().context(\"Could not read HEAD\")?;\n    let oid = head.id().context(\"Repository HEAD is unborn\")?.to_string();\n    let reference = head\n        .referent_name()\n        .map(|name| {\n            name.as_bstr()\n                .to_str()\n                .context(\"HEAD reference name is not UTF-8\")\n                .map(ToOwned::to_owned)\n        })\n        .transpose()?;","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-debug/src/command/dump/repo_installer.rs#L141-L177","documentation":"When building the repo-installer dump, clone_remote() reads the repository's remote URL and rejects URLs containing control characters (newline, carriage return, NUL). This is a safety check before the URL is embedded in archive metadata/scripts.","triggerScenarios":"Running `but-debug dump repo-installer` on a repository whose origin/clone remote URL string contains \\n, \\r, or \\0 — typically from a corrupted or hand-edited .git/config or a path-derived remote.","commonSituations":"Manually edited .git/config with a wrapped line; remotes set from scripts without sanitization; weirdly named local directories joined into the remote path.","solutions":["Inspect and fix the remote: `git remote -v`, then `git remote set-url origin <clean-url>`.","Edit .git/config to remove embedded newlines/control characters in the remote URL.","Re-add the remote: `git remote remove origin && git remote add origin <url>`."],"exampleFix":"// before (.git/config)\n[remote \"origin\"]\n    url = https://example.com/repo.git\n// after (fixed, no stray newline/control chars)\ngit remote set-url origin https://example.com/repo.git","handlingStrategy":"validation","validationCode":"const url = execSync('git -C repo config --get remote.origin.url').toString();\nif (/[\\n\\r\\0]/.test(url)) throw new Error('Remote URL contains control characters; fix with git remote set-url');","typeGuard":"const isCleanUrl = (u) => typeof u === 'string' && u.length > 0 && !/[\\n\\r\\0]/.test(u);","tryCatchPattern":null,"preventionTips":["Never hand-edit .git/config URLs with unescaped newlines.","Sanitize URLs in scripts that call `git remote set-url`.","Audit remotes with `git config --get-regexp 'remote\\..*\\.url'`."],"tags":["git","url","validation"],"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"}