gitbutlerapp/gitbutler · error
Clone remote URL contains unsupported control characters
Error message
Clone remote URL contains unsupported control characters
What it means
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.
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>`.
Example fix
// before (.git/config)
[remote "origin"]
url = https://example.com/repo.git
// after (fixed, no stray newline/control chars)
git remote set-url origin https://example.com/repo.git Defensive patterns
Strategy: validation
Validate before calling
const url = execSync('git -C repo config --get remote.origin.url').toString();
if (/[\n\r\0]/.test(url)) throw new Error('Remote URL contains control characters; fix with git remote set-url'); Type guard
const isCleanUrl = (u) => typeof u === 'string' && u.length > 0 && !/[\n\r\0]/.test(u);
Prevention
- 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'`.
When it happens
Trigger: 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.
Common situations: Manually edited .git/config with a wrapped line; remotes set from scripts without sanitization; weirdly named local directories joined into the remote path.
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
- Aborting due to empty branch name
- Branch name ' ' collides with existing branch
- Can only check out local branches under refs/heads, got
- Can only check out local branches under refs/heads or…
- Can only delete local branches under refs/heads, got
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/0a68b37ae6f7a0bf.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-debug/src/command/dump/repo_installer.rs:159
let remote_url = remote
.url(gix::remote::Direction::Fetch)
.with_context(|| format!("Clone remote '{name}' has no fetch URL"))?;
let mut url = remote_url
.to_bstring()
.to_str()
.context("Clone remote URL is not UTF-8")?
.to_owned();
if remote_url.scheme == gix::url::Scheme::File
&& remote_url.serialize_alternative_form
&& Path::new(&url).is_relative()
{
url = workdir
.join(&url)
.to_str()
.context("Absolute clone remote path is not UTF-8")?
.to_owned();
}
ensure!(
!url.contains(['\n', '\r', '\0']),
"Clone remote URL contains unsupported control characters"
);
Ok(CloneRemote { name, url })
}
fn head(repo: &gix::Repository) -> Result<(String, Option<String>)> {
let head = repo.head().context("Could not read HEAD")?;
let oid = head.id().context("Repository HEAD is unborn")?.to_string();
let reference = head
.referent_name()
.map(|name| {
name.as_bstr()
.to_str()
.context("HEAD reference name is not UTF-8")
.map(ToOwned::to_owned)
})
.transpose()?;View on GitHub (pinned to 58e5313667)