{"record":{"id":"3fb48c44aae82fd5","repo":"nikivdev/code","slug":"host-must-be-a-hostname-like-linsa-localhost","errorCode":null,"errorMessage":"Host must be a hostname like linsa.localhost","messagePattern":"Host must be a hostname like linsa\\.localhost","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/domains.rs","lineNumber":281,"sourceCode":"        }\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://\") {\n        target = stripped.to_string();\n    }\n    target = target.trim_end_matches('/').to_string();","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/domains.rs#L263-L299","documentation":"normalize_host enforces that hosts are plain hostnames. If the sanitized input still contains a slash, a colon (port/scheme), or whitespace, it cannot be a hostname key, so the command bails with this example-formatted message.","triggerScenarios":"Passing values like \"linsa.localhost:3000\", \"linsa.localhost/\", \"http://linsa.localhost/x\", or a host containing spaces to domains get/add/rm.","commonSituations":"Including the port with the host (ports belong in the target), pasting a full URL with a path, or accidental whitespace from shell quoting.","solutions":["Remove any port, path, or scheme — pass only the bare hostname","Put the port in the target argument instead (e.g. `f domains add linsa.localhost :3000`)","Trim the input string before invoking the command"],"exampleFix":"// before\nf domains add linsa.localhost:3000\n// after\nf domains add linsa.localhost :3000","handlingStrategy":"validation","validationCode":"let h = raw.trim().trim_start_matches(\"http://\").trim_start_matches(\"https://\").trim_end_matches('/');\nif h.contains('/') || h.contains(':') || h.contains(char::is_whitespace) {\n    return Err(\"pass a bare hostname like linsa.localhost (no port/path/spaces)\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never embed ports in the host; put them in the target","Strip URLs to just the hostname before calling","Validate with a regex like ^[a-z0-9-]+(\\.[a-z0-9-]+)*$ in wrappers"],"tags":["validation","domains","input"],"backgroundTag":"invalid-input","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}