{"record":{"id":"8fb9b2c7ec82f981","repo":"shadow1ng/fscan","slug":"fscan-target-cannot-set-both-host-and-url","errorCode":null,"errorMessage":"fscan: target cannot set both Host and URL","messagePattern":"fscan: target cannot set both Host and URL","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/fscan/scanner.go","lineNumber":350,"sourceCode":"\nfunc validateConfig(config Config, targets []Target) error {\n\tif len(targets) == 0 {\n\t\treturn fmt.Errorf(\"fscan: at least one target is required\")\n\t}\n\tfor _, name := range normalizePlugins(config.Plugins) {\n\t\tif !plugins.Exists(name) {\n\t\t\treturn fmt.Errorf(\"fscan: plugin %q not found\", name)\n\t\t}\n\t\tif !config.AllowUnsafePlugins && !IsSafePlugin(name) {\n\t\t\treturn fmt.Errorf(\"fscan: plugin %q is not enabled for embedded safe mode\", name)\n\t\t}\n\t}\n\tfor _, target := range targets {\n\t\tif strings.TrimSpace(target.Host) == \"\" && strings.TrimSpace(target.URL) == \"\" {\n\t\t\treturn fmt.Errorf(\"fscan: target host or URL is required\")\n\t\t}\n\t\tif strings.TrimSpace(target.Host) != \"\" && strings.TrimSpace(target.URL) != \"\" {\n\t\t\treturn fmt.Errorf(\"fscan: target cannot set both Host and URL\")\n\t\t}\n\t\tfor _, port := range target.Ports {\n\t\t\tif port < 1 || port > 65535 {\n\t\t\t\treturn fmt.Errorf(\"fscan: invalid port %d\", port)\n\t\t\t}\n\t\t}\n\t}\n\tfor _, port := range config.Ports {\n\t\tif port < 1 || port > 65535 {\n\t\t\treturn fmt.Errorf(\"fscan: invalid port %d\", port)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc buildFlagVars(config Config, target Target) *common.FlagVars {\n\ttimeout := secondsOrDefault(config.Timeout, common.DefaultTimeout)\n\twebTimeout := secondsOrDefault(config.WebTimeout, 5)","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/pkg/fscan/scanner.go#L332-L368","documentation":"validateConfig in pkg/fscan/scanner.go enforces that each scan Target identifies itself either by Host or by URL, never both. Setting both is ambiguous (the scanner cannot decide which form to normalize into fscan's flag variables), so the config is rejected before any scan starts. This is a fail-fast precondition check run by ValidateConfig and scanEach.","triggerScenarios":"Calling ValidateConfig(config) or Scan/scanEach where targets contains a Target whose Host is a non-empty string AND whose URL is a non-empty string simultaneously.","commonSituations":"Populating Target structs from YAML/JSON where both fields were copied from a template; programmatically building targets from a host inventory that also recorded a scheme'd URL; reusing a struct filled by a previous code path that set URL and then adding Host for a port sweep.","solutions":["Set only Host (with Ports) for raw host/port scanning; clear URL.","Set only URL when scanning an HTTP endpoint; clear Host and let the scanner parse it.","Add a pre-submit check in your tooling that rejects Targets with both fields set.","If you truly need both host and URL info, derive the URL from Host at call time instead of passing both."],"exampleFix":"// before\ntargets := []fscan.Target{{Host: \"10.0.0.5\", URL: \"http://10.0.0.5:8080\"}}\n// after\ntargets := []fscan.Target{{URL: \"http://10.0.0.5:8080\"}}\n// or for port scanning:\ntargets := []fscan.Target{{Host: \"10.0.0.5\", Ports: []int{80, 8080}}}","handlingStrategy":"validation","validationCode":"for i, t := range targets {\n    if strings.TrimSpace(t.Host) != \"\" && strings.TrimSpace(t.URL) != \"\" {\n        return fmt.Errorf(\"target[%d]: set either Host or URL, not both\", i)\n    }\n}","typeGuard":"func hasAmbiguousTarget(t fscan.Target) bool {\n    return strings.TrimSpace(t.Host) != \"\" && strings.TrimSpace(t.URL) != \"\"\n}","tryCatchPattern":"if err := fscan.ValidateConfig(cfg); err != nil {\n    if strings.Contains(err.Error(), \"cannot set both Host and URL\") {\n        // fix target definitions before retry\n    }\n    return err\n}","preventionTips":["Use constructor helpers that take either a host or a URL, never raw struct literals.","Add a CI/config-lint rule rejecting Target objects with both fields populated.","Clear the sibling field whenever you populate one of Host/URL."],"tags":["fscan","config-validation","scanner"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}