How to Debug Module Failures and Handle Errors in SpiderFoot
Enable verbose logging with -d, check ~/.spiderfoot/logs for stack traces, and validate that modules have correct filenames, single categories, and properly formatted asdict() methods.
SpiderFoot is an open-source reconnaissance framework that dynamically loads hundreds of plugin modules at runtime. When modules fail to load, crash during execution, or produce unexpected results, understanding the underlying architecture is essential for rapid diagnosis. This guide walks through the exact locations in the source code where failures occur and provides specific steps to debug module failures and handle errors in SpiderFoot.
Where Module Failures Originate
SpiderFoot's architecture separates concerns across several key components. Knowing which layer produces an error lets you focus debugging effort efficiently.
| Component | Responsibility | Typical Failure Points |
|---|---|---|
sf.py – Main entry point |
Parses CLI arguments, creates global config, loads modules, starts scans or web UI | Invalid CLI options, missing config values, web server startup failures |
spiderfoot/helpers.py |
Provides loadModulesAsDict() which imports each module under modules/ |
Syntax errors, duplicate categories, missing sfp_ prefix, malformed asdict() |
Individual modules (modules/sfp_*.py) |
Contain data-gathering logic; must expose asdict() and implement required interface |
Runtime exceptions, API key issues, incorrect provides/consumes definitions |
SpiderFootDb |
Persists scan results and configuration | File permission problems, corrupted schema |
| Logging subsystem | Collects debug/error information | Disabled logging, missing log directory |
Debugging Module Loading Failures
How Modules Are Loaded
In sf.py at line 141, modules are imported via:
sfModules = SpiderFootHelpers.loadModulesAsDict(mod_dir, ['sfp_template.py'])
The actual import logic resides in spiderfoot/helpers.py → loadModulesAsDict (lines 21-73). This function:
- Scans
modules/for files matchingsfp_*.py - Imports each with
__import__('modules.' + modName, ...) - Instantiates the class and calls
asdict()to validate structure
Source: sf.py#L141 and helpers.py#L21-L73
Common Loading Errors and Fixes
| Symptom | Root Cause | Solution |
|---|---|---|
log.critical("Failed to load modules …") |
Syntax error or exception in module class definition | Run with -d flag and examine traceback in console or ~/.spiderfoot/logs |
SyntaxError: Module … has multiple categories defined |
cats list contains more than one entry |
Change cats = ["A", "B"] to cats = ["Category"] — single string only |
SyntaxError: Module … has invalid category |
Category not in valid_categories whitelist |
Match one of the allowed values (helpers.py lines 46-49) |
ImportError: No module named … |
Missing third-party dependency | Install from requirements.txt: pip install -r requirements.txt |
To verify a module loads correctly after fixes:
spiderfoot -M
This lists all successfully loaded modules.
Validating Module Structure
Each module must satisfy three requirements:
- Filename matches class name:
sfp_example.py→class sfp_example asdict()returns required keys:name,descr,provides,consumes,cats- Single valid category: Must appear in
valid_categories(e.g.,"DNS","SOCIAL")
Quick validation command:
python -c "
import importlib
mod = importlib.import_module('modules.sfp_example')
obj = getattr(mod, 'sfp_example')()
print(obj.asdict())
"
If this raises an exception, the asdict() method needs correction.
Debugging Runtime Scan Failures
Where Scans Launch
The start_scan function in sf.py (lines 235-261) creates a SpiderFoot instance and spawns sfscan.startSpiderFootScanner in a separate process.
Source: sf.py#L235-L261
Common Runtime Issues
| Error Message | Cause | Fix |
|---|---|---|
You must specify a target |
Missing -s argument |
Add target: spiderfoot -s example.com |
Could not determine target type |
Target format unrecognized | Use valid format per targetTypeFromString (helpers.py lines 22-38): IP, domain, CIDR, ASN, email, phone, username, or bitcoin address |
Modules enabled … shows empty list |
-x (strict mode) filtered all modules |
Remove -x or adjust -t to include compatible event types |
Failed to initialize database |
Permission denied on ~/.spiderfoot/spiderfoot.db |
Create directory with mkdir -p ~/.spiderfoot && chmod 700 ~/.spiderfoot |
requests.exceptions.ConnectTimeout |
External API unreachable or missing API key | Test endpoint manually; store keys in ~/.spiderfoot/config |
Essential Debug Flags
-d: Enable debug output (sets_debug = Trueinternally)-o json: Structured output for log parsing-max-threads 1: Reduce concurrency to simplify traceback analysis
Debug execution example:
spiderfoot -d -s example.com -o json 2> spiderfoot_debug.log
Log files are stored in ~/.spiderfoot/logs/ with timestamps: spiderfoot-<timestamp>.log
Debugging Correlation Rule Errors
Correlation rules load in sf.py (lines 53-57) via loadCorrelationRulesRaw. Failures appear as:
log.critical("Failed to load correlation rules: …")
Common causes:
- YAML syntax errors in
correlations/*.yamlfiles - Missing required fields:
description,events
Validate rule files with any YAML linter and compare against repository examples.
Step-by-Step Debugging Workflow
# 1. Run with maximum verbosity, capture all output
spiderfoot -d -s example.com -o json > scan_output.json 2> spiderfoot_debug.log
# 2. Find first critical error in logs
grep -i "error\|critical\|failed" spiderfoot_debug.log | head -5
# 3. Inspect offending module (example: sfp_dnsresolve)
sed -n '1,120p' modules/sfp_dnsresolve.py
# 4. Validate asdict() returns proper structure
python - <<'PY'
import sys
sys.path.insert(0, '.')
import importlib
mod = importlib.import_module('modules.sfp_dnsresolve')
cls = getattr(mod, 'sfp_dnsresolve')
print(cls().asdict())
PY
# 5. Check database permissions if DB errors occur
ls -la ~/.spiderfoot/spiderfoot.db
sqlite3 ~/.spiderfoot/spiderfoot.db ".tables"
For HTTP-related failures, set SPIDERFOOT_LOGS environment variable to a writable directory. Most modules log request URLs when _debug is enabled.
Key Source Files for Debugging
| File | Purpose | Direct Link |
|---|---|---|
sf.py |
CLI driver, module loading, scan orchestration | sf.py |
spiderfoot/helpers.py |
loadModulesAsDict(), targetTypeFromString() |
helpers.py |
modules/sfp_template.py |
Reference module skeleton | sfp_template.py |
sfscan.py |
Worker process running selected modules | sfscan.py |
spiderfoot/__init__.py |
Core SpiderFoot and SpiderFootDb classes |
spiderfoot/init.py |
requirements.txt |
Third-party dependencies | requirements.txt |
Summary
- Run SpiderFoot with
-dto capture full stack traces in~/.spiderfoot/logs - Ensure module filenames start with
sfp_and class names match exactly - Verify
catscontains one valid category from the whitelist - Confirm
asdict()returns a dictionary withname,descr,provides,consumes, andcats - Check target strings against
targetTypeFromStringregex patterns - Validate database file permissions and directory ownership
- Use
-max-threads 1to reduce noise in concurrent failure scenarios
Frequently Asked Questions
Where does SpiderFoot store debug logs?
SpiderFoot writes logs to ~/.spiderfoot/logs/ with filenames following the pattern spiderfoot-<timestamp>.log. When running with -d, debug output also appears on stderr. Set the SPIDERFOOT_LOGS environment variable to override the log directory location.
Why does my custom module fail to load with "multiple categories defined"?
The loadModulesAsDict() function in spiderfoot/helpers.py enforces a single category per module. Change your module's cats variable from a list with multiple strings (["DNS", "SEARCH"]) to a single-element list (["DNS"]). The whitelist of valid categories is defined at helpers.py lines 46-49.
How do I identify which module is causing a scan to crash?
Run with -d -max-threads 1 to serialize execution and capture un-interleaved tracebacks. Examine the log for the last module name printed before the exception, or search for Module [sfp_ to find module start/end markers. Most modules log entry points when _debug is enabled.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →