{"record":{"id":"749bff76763475cd","repo":"projectdiscovery/subfinder","slug":"v-749bff","errorCode":null,"errorMessage":"%v","messagePattern":"%v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/subscraping/sources/shodan/shodan.go","lineNumber":85,"sourceCode":"\t\t\t\tresults <- subscraping.Result{Source: s.Name(), Type: subscraping.Error, Error: err}\n\t\t\t\ts.errors++\n\t\t\t\tsession.DiscardHTTPResponse(resp)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tdefer session.DiscardHTTPResponse(resp)\n\n\t\t\tvar response dnsdbLookupResponse\n\t\t\terr = jsoniter.NewDecoder(resp.Body).Decode(&response)\n\t\t\tif err != nil {\n\t\t\t\tresults <- subscraping.Result{Source: s.Name(), Type: subscraping.Error, Error: err}\n\t\t\t\ts.errors++\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif response.Error != \"\" {\n\t\t\t\tresults <- subscraping.Result{\n\t\t\t\t\tSource: s.Name(), Type: subscraping.Error, Error: fmt.Errorf(\"%v\", response.Error),\n\t\t\t\t}\n\t\t\t\ts.errors++\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfor _, data := range response.Subdomains {\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tdefault:\n\t\t\t\t}\n\t\t\t\tvalue := fmt.Sprintf(\"%s.%s\", data, response.Domain)\n\t\t\t\tresults <- subscraping.Result{\n\t\t\t\t\tSource: s.Name(), Type: subscraping.Subdomain, Value: value,\n\t\t\t\t}\n\t\t\t\ts.results++\n\t\t\t\tif maxResults > 0 && s.results >= maxResults {\n\t\t\t\t\treturn","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/projectdiscovery/subfinder/blob/7a0b91f0fac01b62c65328bd771a3560ae611d6a/pkg/subscraping/sources/shodan/shodan.go#L67-L103","documentation":"The shodan source forwards the API's own error string verbatim (%v of response.Error) as an Error Result. Shodan returns an \"error\" field in its JSON whenever the request is rejected — invalid key, rate limit, or bad query — and the library surfaces that message directly to the caller.","triggerScenarios":"The Shodan API responds with JSON whose Error field is non-empty, e.g. \"invalid API key\", \"403 Forbidden: insufficient credits\", or rate-limit messages from https://api.shodan.io during enumeration.","commonSituations":"Missing or expired SHODAN_API_KEY; free-tier key lacking access to the subdomain/DNS endpoints; hitting Shodan's per-second or monthly credit limits.","solutions":["Check that a valid SHODAN_API_KEY is set in the environment or provider config.","Verify the key has access to Shodan's DNS/subdomains endpoint (requires a paid plan or credits).","Slow down or retry later if the message indicates rate limiting."],"exampleFix":"// before: key missing\nexport PATH=...\n// after: export valid key\nexport SHODAN_API_KEY=xxxxxxxxxxxxxxxx\n","handlingStrategy":"try-catch","validationCode":"if os.Getenv(\"SHODAN_API_KEY\") == \"\" { return errors.New(\"SHODAN_API_KEY not set\") }","typeGuard":null,"tryCatchPattern":"for r := range results {\n  if r.Type == subscraping.Error {\n    if strings.Contains(r.Error.Error(), \"invalid API key\") {\n      // fix key and re-run\n    } else if strings.Contains(r.Error.Error(), \"rate\") {\n      // backoff and retry\n    }\n  }\n}","preventionTips":["Validate the Shodan key before starting a scan (hit a cheap endpoint once).","Respect Shodan's rate limits (max ~1 req/sec on free plans).","Monitor API credit usage; Shodan DNS access requires a paid plan."],"tags":["network","api-key","shodan","api-error"],"backgroundTag":"api-error-response","analyzedSha":"7a0b91f0fac01b62c65328bd771a3560ae611d6a","analyzedAt":"2026-09-06T23:52:02.109Z","contentChangedAt":"2026-09-06T23:52:02.109Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}