GitoxideLabs/gitoxide · error
git daemon virtual hosts must not contain NUL or LF
Error message
git daemon virtual hosts must not contain NUL or LF
What it means
Like the path check, the `git://` transport rejects virtual host names (the `virtual_host` argument) containing NUL (`\0`) or LF (`\n`), since these bytes cannot appear in the protocol's `host=` extra parameter. Fails with `InvalidInput` before any network I/O.
Solutions
- Trim the host string before passing it as a virtual host
- Validate the host contains only printable characters (no NUL/LF) at parse time
- Fix parsers that fail to strip line endings from config/input
Example fix
// before let vhost = Some((line.to_string(), None)); // line ends with '\n' // after let vhost = Some((line.trim().to_string(), None));
Defensive patterns
Strategy: validation
Validate before calling
fn validate_vhost(host: &str) -> Result<(), String> {
if host.bytes().any(|b| b == b'\0' || b == b'\n') {
Err("virtual host contains NUL or LF".into())
} else { Ok(()) }
} Try / catch
match gix::connect(url, gix::protocol::transport::Protocol::Git) {
Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => {
eprintln!("check virtual host input: {e}");
}
other => other?,
} Prevention
- Trim line endings from hosts parsed from config files
- Validate hostnames against a printable-ASCII pattern before use
- Never pass user-supplied raw lines as virtual host names
When it happens
Trigger: Calling `gix::connect()` with `Some((host, port))` as virtual host where `host` contains a NUL or newline byte.
Common situations: Parsing a virtual host from raw input (config lines, files) without trimming; string splitting bugs that keep a trailing newline in the host part.
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
- git daemon repository paths must not contain NUL or LF
- Tried to use as tree, but was
- Tried to use as commit, but was
- Tried to use as tag, but was
- invalid mode change: can't flip executable bit of
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/e257248677790e31.
Report an issue: GitHub.
Appendix: source
Thrown at gix-transport/src/client/git/mod.rs:44
use crate::{Protocol, Service};
pub fn connect(
service: Service,
desired_version: Protocol,
path: &[u8],
virtual_host: Option<&(String, Option<u16>)>,
extra_parameters: &[(&str, Option<&str>)],
) -> std::io::Result<BString> {
let path = gix_url::expand_path::for_shell(path.into());
let is_forbidden = |byte| matches!(byte, b'\0' | b'\n');
if path.iter().copied().any(is_forbidden) {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"git daemon repository paths must not contain NUL or LF",
));
}
if virtual_host.is_some_and(|(host, _)| host.bytes().any(is_forbidden)) {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"git daemon virtual hosts must not contain NUL or LF",
));
}
let mut out = bstr::BString::from(service.as_str());
out.push(b' ');
out.extend_from_slice(&path);
out.push(0);
if let Some((host, port)) = virtual_host {
out.push_str("host=");
out.extend_from_slice(host.as_bytes());
if let Some(port) = port {
out.push_byte(b':');
out.push_str(format!("{port}"));
}
out.push(0);
}View on GitHub (pinned to e73179060b)