{"record":{"id":"5cc9c25c2d725ee6","repo":"shadow1ng/fscan","slug":"parse-error-first-line-must-start-with-probe-o","errorCode":null,"errorMessage":"Parse error: first line must start with \"Probe \" or \"Exclude \"","messagePattern":"Parse error: first line must start with \"Probe \" or \"Exclude \"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/portfinger/probe_parser.go","lineNumber":201,"sourceCode":"\tif len(lines) == 0 {\n\t\treturn fmt.Errorf(\"%s\", i18n.GetText(\"portfinger_probe_file_empty\"))\n\t}\n\n\t// 检查Exclude指令\n\texcludeCount := 0\n\tfor _, line := range lines {\n\t\tif strings.HasPrefix(line, \"Exclude \") {\n\t\t\texcludeCount++\n\t\t}\n\t\tif excludeCount > 1 {\n\t\t\treturn fmt.Errorf(\"%s\", i18n.GetText(\"portfinger_probe_exclude_duplicate\"))\n\t\t}\n\t}\n\n\t// 验证第一行格式\n\tfirstLine := lines[0]\n\tif !strings.HasPrefix(firstLine, \"Exclude \") && !strings.HasPrefix(firstLine, \"Probe \") {\n\t\treturn fmt.Errorf(\"%s\", i18n.GetText(\"portfinger_probe_first_line_invalid\"))\n\t}\n\n\t// 处理Exclude指令\n\tif excludeCount == 1 {\n\t\tv.Exclude = firstLine[len(\"Exclude\")+1:]\n\t\tlines = lines[1:]\n\t}\n\n\t// 合并内容并分割探测器\n\tcontent = \"\\n\" + strings.Join(lines, \"\\n\")\n\tprobeParts := strings.Split(content, \"\\nProbe\")[1:]\n\n\t// 解析每个探测器\n\tfor _, probePart := range probeParts {\n\t\tprobe := Probe{}\n\t\tif err := probe.fromString(probePart); err != nil {\n\t\t\tcontinue\n\t\t}","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/core/portfinger/probe_parser.go#L183-L219","documentation":"The probe database's first meaningful line must be either an \"Exclude \" directive or a \"Probe \" directive. When lines[0] starts with anything else the parser returns this error, as the file structure cannot be interpreted from that point on. (The raw message shown is the resolution of the i18n key portfinger_probe_first_line_invalid.)","triggerScenarios":"Init/parseProbesFromContent reads a probe file whose first non-empty line is neither \"Exclude ...\" nor \"Probe ...\" — e.g. a comment, blank-line artifact that wasn't skipped, header text, or a lowercase/mangled directive.","commonSituations":"Manually added README/comment lines at the top of the probe file, files converted from nmap-service-probes (different grammar), or corrupted downloads where the initial line was lost.","solutions":["Make the first line of the probe file start with \"Exclude \" or \"Probe \" (exact case and trailing space).","Remove any comments, headers, or junk lines above the first probe definition.","If converting from nmap's probe format, rewrite lines into this parser's \"Probe <proto> <name>...\" grammar.","Validate the file with a pre-check that asserts the first line prefix before calling Init."],"exampleFix":"// before (probe file)\n# probe database v2\nProbe tcp GetHttp ...\n// after\nProbe tcp GetHttp ...   (no leading comment/header lines)","handlingStrategy":"validation","validationCode":"first := firstNonEmptyLine(content)\nif !strings.HasPrefix(first, \"Probe \") && !strings.HasPrefix(first, \"Exclude \") {\n    return fmt.Errorf(\"probe file must start with 'Probe ' or 'Exclude '\")\n}","typeGuard":null,"tryCatchPattern":"if err := pf.Init(path); err != nil && strings.Contains(err.Error(), \"first line must start with\") {\n    return fmt.Errorf(\"probe file %s has invalid first line: %w\", path, err)\n}","preventionTips":["Never put comments or headers at the top of probe files","Generate probe files programmatically to guarantee structure","Validate the first line prefix in CI before distribution"],"tags":["portfinger","parsing","file-format","validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}