frappe-agent-debugger
Installation
SKILL.md
Frappe Debugging Agent
Systematically diagnoses Frappe/ERPNext issues by classifying errors, locating relevant code, and applying targeted diagnosis checklists.
Purpose: Eliminate trial-and-error debugging — follow a deterministic diagnostic workflow.
When to Use This Agent
ERROR ANALYSIS TRIGGER
|
+-- Python traceback or error message
| "ImportError: cannot import name X from frappe"
| --> USE THIS AGENT
|
+-- JavaScript console error
| "Uncaught TypeError: frm.set_value is not a function"
| --> USE THIS AGENT
|
+-- Silent failure (no error, wrong behavior)
| "Server Script runs but nothing happens"
| --> USE THIS AGENT
|
+-- Scheduler/background job failure
| "Job X failed" in scheduler logs
| --> USE THIS AGENT
|
+-- Build/asset errors
| "Module not found" or blank page after build
| --> USE THIS AGENT
Debugging Workflow
STEP 1: CLASSIFY ERROR TYPE
Python | JavaScript | Database | Permission | Hook | Scheduler | Build
STEP 2: IDENTIFY THE MECHANISM
Controller | Server Script | Client Script | Hook | Scheduler | API
STEP 3: LOCATE RELEVANT CODE
Use Frappe file path conventions to find source
STEP 4: APPLY DIAGNOSIS CHECKLIST
Run type-specific checklist for the error class
STEP 5: SUGGEST FIX
Provide corrected code + reference relevant frappe-* skills
See references/workflow.md for detailed steps.
Step 1: Error Classification
| Error Type | Indicators | Primary Tool |
|---|---|---|
| Python | Traceback with .py files |
bench console, logs |
| JavaScript | Browser console error, cur_frm issues |
Browser DevTools |
| Database | OperationalError, IntegrityError |
bench mariadb |
| Permission | frappe.PermissionError, 403 responses |
Permission Inspector |
| Hook | Errors after bench migrate, wrong events |
bench doctor |
| Scheduler | bench doctor warnings, RQ failures |
Scheduler logs |
| Build | Missing assets, blank page, module errors | bench build --verbose |
Step 2: Mechanism Identification
| Symptom | Likely Mechanism |
|---|---|
| Error during form save/submit | Controller or Server Script (validate/on_submit) |
| Error on page load | Client Script or Web Template |
| Error message from API call | Whitelisted method or REST API handler |
| Error in background | Scheduler event or frappe.enqueue() job |
Error after bench migrate |
Hook configuration or patch |
Error after bench build |
Frontend asset pipeline |
Step 3: File Path Conventions
ALWAYS check these locations based on the mechanism:
| Mechanism | File Path Pattern |
|---|---|
| Controller | apps/{app}/{app}/{module}/{doctype}/{doctype}.py |
| Server Script | Desk > Server Script list (stored in DB) |
| Client Script | Desk > Client Script list (stored in DB) |
| hooks.py | apps/{app}/{app}/hooks.py |
| Scheduler | apps/{app}/{app}/tasks.py or hooks.py scheduler_events |
| Whitelisted | apps/{app}/{app}/{module}/*.py (search for @frappe.whitelist) |
| Jinja | apps/{app}/{app}/templates/ |
| Patches | apps/{app}/{app}/patches/ |
Step 4: Diagnosis Checklists (Quick Reference)
Python Errors
| Error Pattern | Likely Cause | Fix |
|---|---|---|
AttributeError: 'NoneType' |
frappe.get_doc() returned None |
Check document exists first |
ValidationError |
frappe.throw() in validate |
Read the message — it IS the diagnosis |
ImportError |
Wrong import path or Server Script using imports | Server Scripts CANNOT import |
LinkValidationError |
Referenced document does not exist | Verify Link field target exists |
TimestampMismatchError |
Concurrent edit conflict | Reload document before save |
DuplicateEntryException |
Unique constraint violation | Check naming series or unique fields |
MandatoryError |
Required field is empty | Set field before save/submit |
InvalidStatusError |
Wrong docstatus transition | Follow 0→1→2 sequence |
CircularLinkingError |
Self-referencing parent-child | Fix document hierarchy |
JavaScript Errors
| Error Pattern | Likely Cause | Fix |
|---|---|---|
frm.X is not a function |
Wrong API or stale code | Clear cache, check API name |
cur_frm is undefined |
Code runs outside form context | Use frm from handler parameter |
Uncaught Promise |
Missing async/await on frappe.call |
Add callback or await |
field undefined in frm.doc |
Field does not exist on DocType | Check fieldname spelling |
| Form not refreshing | Missing frm.refresh_fields() |
Add refresh after set_value |
Database Errors
| Error Pattern | Likely Cause | Fix |
|---|---|---|
OperationalError: 1054 |
Column does not exist | Run bench migrate |
OperationalError: 1146 |
Table does not exist | Run bench migrate |
IntegrityError: 1062 |
Duplicate primary key | Check naming/autoname |
IntegrityError: 1452 |
Foreign key violation | Linked document missing |
OperationalError: 1213 |
Deadlock | Reduce transaction scope |
InternalError: 1366 |
Invalid character for charset | Check input encoding |
Permission Errors
| Error Pattern | Likely Cause | Fix |
|---|---|---|
frappe.PermissionError |
User lacks role permission | Check Role Permission Manager |
| 403 on API call | Missing frappe.has_permission() or wrong @frappe.whitelist(allow_guest=True) |
Add permission check or guest flag |
| Empty list view | User Permissions filtering | Check User Permission for that user |
| Cannot submit | No Submit permission for role | Add Submit perm in DocType |
Debug Tools
bench console (Python REPL)
bench --site {site} console
# Then:
frappe.get_doc("Sales Invoice", "SINV-00001") # Inspect document
frappe.db.sql("SELECT name FROM `tabSales Invoice` LIMIT 5") # Raw SQL
frappe.get_hooks("doc_events") # Inspect active hooks
frappe.get_all("Server Script", filters={"disabled": 0}, fields=["name", "script_type"])
bench mariadb (SQL shell)
bench --site {site} mariadb
-- Then:
SHOW CREATE TABLE `tabSales Invoice`;
SELECT * FROM `tabError Log` ORDER BY creation DESC LIMIT 10;
bench doctor
bench doctor # Check scheduler, workers, background jobs
frappe.logger()
logger = frappe.logger("my_debug", allow_site=True)
logger.info(f"Variable value: {my_var}")
# Logs to: sites/{site}/logs/my_debug.log
Browser DevTools
Console tab → JavaScript errors
Network tab → Failed API calls (check response body for traceback)
Application tab → Session/cookie issues
Log File Locations
| Log | Path | Contains |
|---|---|---|
| Frappe web | sites/{site}/logs/frappe.log |
Web request errors |
| Worker | sites/{site}/logs/worker.log |
Background job errors |
| Scheduler | sites/{site}/logs/scheduler.log |
Scheduled task output |
| Custom logger | sites/{site}/logs/{name}.log |
frappe.logger("{name}") output |
| Bench | ~/.bench/logs/bench.log |
Bench command output |
| Error Log DocType | Desk > Error Log | UI-accessible error records |
| Supervisor | /var/log/supervisor/ |
Process manager logs |
| nginx | /var/log/nginx/ |
HTTP request/proxy errors |
Common Error Patterns Table
| Error Message | Likely Cause | Fix | Relevant Skill |
|---|---|---|---|
Import not allowed in Server Scripts |
Using import in Server Script |
Use frappe.utils.* or move to Controller |
frappe-errors-serverscripts |
Cannot read properties of undefined |
JS accessing field before form load | Add frm.doc.field null check |
frappe-errors-clientscripts |
DocType X not found |
Missing app install or migration | bench migrate or bench install-app |
frappe-ops-bench |
Scheduler is not running |
Workers stopped | bench doctor, restart workers |
frappe-ops-bench |
BrokenPipeError |
gunicorn timeout on long operation | Use frappe.enqueue() for long tasks |
frappe-impl-scheduler |
ModuleNotFoundError |
Python package not installed | bench pip install {pkg} |
frappe-ops-bench |
Duplicate name |
Name collision in naming series | Check autoname or naming_series | frappe-syntax-doctypes |
Insufficient Permission |
Missing role for operation | Check Role Permissions | frappe-core-permissions |
Cannot edit submitted document |
Modifying docstatus=1 doc | Use amend_doc() or cancel first |
frappe-errors-controllers |
Invalid column |
Schema out of sync | bench migrate |
frappe-errors-database |
Agent Output Format
ALWAYS produce debugging output in this format:
## Debug Report
### Error Classification
**Type**: [Python/JS/Database/Permission/Hook/Scheduler/Build]
**Mechanism**: [Controller/Server Script/Client Script/Hook/etc.]
### Root Cause
[One-sentence diagnosis]
### Evidence
- [What log/traceback line confirms this]
- [What code path is involved]
### Fix
[Corrected code or configuration change]
### Verification Steps
1. [How to confirm the fix works]
2. [What to check in logs/UI]
### Referenced Skills
- `frappe-*`: [what was consulted]
Debugging Decision Tree
ERROR RECEIVED
|
+-- Has traceback?
| +-- YES: Read LAST line first (actual error)
| | +-- Contains ".py" --> Python error (Step 4: Python checklist)
| | +-- Contains "SQL" --> Database error (Step 4: Database checklist)
| +-- NO: Check browser console
| +-- Has JS error --> JavaScript error (Step 4: JS checklist)
| +-- No error visible --> Silent failure
| +-- Check Error Log DocType
| +-- Check frappe.log
| +-- Add frappe.logger() statements
|
+-- Error after bench command?
| +-- After migrate --> Hook/schema issue
| +-- After build --> Frontend asset issue
| +-- After update --> Version compatibility issue
|
+-- Intermittent error?
+-- Check scheduler logs
+-- Check worker logs
+-- Check for race conditions (TimestampMismatchError)
See references/checklists.md for complete diagnosis checklists. See references/examples.md for debugging walkthrough examples. See references/advanced-debugging.md for VS Code DAP setup, bench console patterns, mariadb diagnostics, and profiling tools.
Related skills