{"record":{"id":"09f0f0c5b7e7a597","repo":"nikivdev/code","slug":"host-is-empty","errorCode":null,"errorMessage":"Host is empty","messagePattern":"Host is empty","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/domains.rs","lineNumber":278,"sourceCode":"        println!(\"{}\", \"-\".repeat(58));\n        for (host, target) in routes {\n            println!(\"{:<32} {}\", host, target);\n        }\n    }\n\n    Ok(())\n}\n\nfn normalize_host(raw: &str) -> Result<String> {\n    let mut host = raw.trim().to_ascii_lowercase();\n    if let Some(stripped) = host.strip_prefix(\"http://\") {\n        host = stripped.to_string();\n    } else if let Some(stripped) = host.strip_prefix(\"https://\") {\n        host = stripped.to_string();\n    }\n    host = host.trim_end_matches('/').to_string();\n    if host.is_empty() {\n        bail!(\"Host is empty\");\n    }\n    if host.contains('/') || host.contains(':') || host.contains(char::is_whitespace) {\n        bail!(\"Host must be a hostname like linsa.localhost\");\n    }\n    if !host.ends_with(\".localhost\") {\n        bail!(\"Host must end with .localhost\");\n    }\n    if host == \".localhost\" || host == \"localhost\" {\n        bail!(\"Host must include a subdomain (for example: linsa.localhost)\");\n    }\n    Ok(host)\n}\n\nfn normalize_target(raw: &str) -> Result<String> {\n    let mut target = raw.trim().to_string();\n    if let Some(stripped) = target.strip_prefix(\"http://\") {\n        target = stripped.to_string();\n    } else if let Some(stripped) = target.strip_prefix(\"https://\") {","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/domains.rs#L260-L296","documentation":"normalize_host sanitizes user-supplied host input before route operations. After stripping scheme prefixes and trailing slashes, if nothing remains the function bails because an empty host cannot be a valid route key.","triggerScenarios":"Passing an empty string, only a scheme (\"http://\"), only slashes (\"/\"), or only whitespace to domains get/add/rm — everything is stripped and the result is empty.","commonSituations":"Shell variable expansion failing ($HOST unset), copy-pasting just \"https://\", or scripting the command with a missing argument that defaults to empty.","solutions":["Pass a full hostname such as linsa.localhost","Check that the shell variable holding the host is actually set/non-empty","Quote the argument so empty expansions fail loudly instead of vanishing"],"exampleFix":"// before\nf domains add \"$HOST\" :3000   # HOST empty -> Host is empty\n// after\nf domains add \"linsa.localhost\" :3000","handlingStrategy":"validation","validationCode":"let host = raw.trim();\nlet host = host.trim_start_matches(\"http://\").trim_start_matches(\"https://\").trim_end_matches('/');\nif host.is_empty() {\n    return Err(\"host argument required, e.g. linsa.localhost\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass an explicit, quoted host argument","Check shell variables are set before expansion (${HOST:?unset})","Reject empty strings in your own wrappers before invoking the CLI"],"tags":["validation","domains","input"],"backgroundTag":"invalid-input","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}