{"record":{"id":"fb6d80848f00c4d5","repo":"usememos/memos","slug":"empty-hostname","errorCode":null,"errorMessage":"empty hostname","messagePattern":"empty hostname","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"internal/httpgetter/html_meta.go","lineNumber":120,"sourceCode":"}\n\nfunc isInternalIP(ip net.IP) bool {\n\treturn ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() || ip.IsUnspecified()\n}\n\nfunc validateURL(urlStr string) error {\n\tu, err := url.Parse(urlStr)\n\tif err != nil {\n\t\treturn errors.New(\"invalid URL format\")\n\t}\n\n\tif u.Scheme != \"http\" && u.Scheme != \"https\" {\n\t\treturn errors.New(\"only http/https protocols are allowed\")\n\t}\n\n\thost := u.Hostname()\n\tif host == \"\" {\n\t\treturn errors.New(\"empty hostname\")\n\t}\n\n\tif ip := net.ParseIP(host); ip != nil && isInternalIP(ip) {\n\t\treturn errors.Wrap(ErrInternalIP, ip.String())\n\t}\n\n\treturn nil\n}\n\ntype HTMLMeta struct {\n\tTitle       string `json:\"title\"`\n\tDescription string `json:\"description\"`\n\tImage       string `json:\"image\"`\n}\n\nfunc GetHTMLMeta(urlStr string) (*HTMLMeta, error) {\n\tif err := validateURL(urlStr); err != nil {\n\t\treturn nil, err","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/internal/httpgetter/html_meta.go#L102-L138","documentation":"validateURL successfully parsed the URL but u.Hostname() returned an empty string, meaning there is no host to resolve or connect to. Typical inputs are scheme-only strings or URLs whose authority section is empty.","triggerScenarios":"URLs like `https:///path` (empty authority), `http://?q=1`, or `https:` alone. Also some relative or malformed inputs that parse but carry no host.","commonSituations":"Programmatic URL construction that concatenates a base and path incorrectly and drops the host; user typos like `https:// /page`; frontends sending the path component only.","solutions":["Fix the URL to include a hostname: `https://example.com/path`","Check client-side URL construction (base join logic) for dropped hosts","Validate with a URL parser requiring a non-empty host before submitting"],"exampleFix":"// before\nGetHTMLMeta(\"https:///notes/1\")\n// after\nGetHTMLMeta(\"https://example.com/notes/1\")","handlingStrategy":"validation","validationCode":"func hasHost(raw string) bool {\n  u, err := url.Parse(strings.TrimSpace(raw))\n  return err == nil && u.Hostname() != \"\"\n}","typeGuard":null,"tryCatchPattern":"// Map to a friendly client error\nif err := fetchPreview(raw); err != nil && strings.Contains(err.Error(), \"empty hostname\") {\n  return errors.New(\"URL is missing its host: include the domain name\")\n}","preventionTips":["Build URLs via url.URL{Scheme, Host, Path} instead of string concatenation","Assert non-empty host before network calls","Test URL construction helpers with table-driven cases"],"tags":["network","url","validation"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}