Skip to content
AI & Agents
Skill

/frappe-errors-hooks

Use when debugging hooks.py errors in Frappe/ERPNext. Covers hook not firing (typo, wrong dict structure), circular imports, app_include_js path errors, scheduler_events not running, doc_events on wrong DocType, permission_query_conditions SQL errors, override_doctype_class

From plugin
frappe-claude-skill-package
17961 skills
Install
$ npx -y skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-errors-hooks --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/frappe-errors-hooks

Context preview

The summary Claude sees to decide when to auto-load this skill.

Use when debugging hooks.py errors in Frappe/ERPNext. Covers hook not firing (typo, wrong dict structure), circular imports, app_include_js path errors, scheduler_events not running, doc_events on wrong DocType, permission_query_conditions SQL errors, override_doctype_class

SKILL.md

frappe-errors-hooks.SKILL.md
name: frappe-errors-hooks
description: >
  Use when debugging hooks.py errors in Frappe/ERPNext. Covers hook not firing
  (typo, wrong dict structure), circular imports, app_include_js path errors,
  scheduler_events not running, doc_events on wrong DocType,
  permission_query_conditions SQL errors, override_doctype_class import
  failures, extend_doctype_class [v16+] conflicts, fixtures not loading.
  Error diagnosis by hook type for v14/v15/v16.
  Keywords: hooks.py error, hook not firing, scheduler not running,, hook not working, scheduler not running, app_include not loading, override not applied.
  doc_events error, circular import, fixtures error, override class error.
license: MIT
compatibility: "Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16."
metadata:
  author: OpenAEC-Foundation
  version: "2.0"

Frappe Hooks Error Diagnosis & Resolution

Cross-ref: `frappe-syntax-hooks` (syntax), `frappe-impl-hooks` (workflows), `frappe-errors-controllers` (controller errors).

---

Error-to-Fix Mapping Table

| Error / Symptom | Cause | Fix | |-----------------|-------|-----| | Hook not firing at all | Typo in dotted path | Verify module path matches actual file location | | `ImportError` on bench start | Wrong module path or circular import | Fix import path; break circular dependency | | `AttributeError: module has no attribute` | Function name typo in hooks.py | Match function name exactly to Python definition | | `app_include_js` not loading | Path missing `assets/` prefix or wrong extension | Use `"assets/myapp/js/file.js"` format | | scheduler_events not running | Scheduler disabled or workers down | `bench scheduler enable`, check `bench doctor` | | doc_events handler never called | DocType name misspelled in dict key | Use exact DocType name with spaces: `"Sales Invoice"` | | `permission_query_conditions` breaks list view | SQL syntax error or frappe.throw() in handler | Return valid SQL string; NEVER throw | | `override_doctype_class` import failure | Parent class import path changed between versions | Pin import to correct module path for target version | | `extend_doctype_class` [v16+] method conflict | Two extensions define same method name | Rename conflicting methods; check hook resolution order | | Fixtures not loading on install | Wrong `dt` key or DocType doesn't exist on target | Verify DocType exists before export; check filter syntax | | `extend_bootinfo` breaks login | Unhandled exception in boot handler | Wrap ALL bootinfo code in try/except | | Wildcard `"*"` handler breaks all saves | Unhandled exception in wildcard doc_events | ALWAYS wrap wildcard handlers in try/except | | Hook fires but changes lost | Missing `frappe.db.commit()` in scheduler | Add explicit commit in scheduler/background tasks | | Multiple handler chain broken | First handler throws, others never run | Isolate non-critical ops in try/except |

---

Hook Registration Errors

Hook Not Firing: Diagnosis Checklist

IS YOUR HOOK NOT FIRING?
│
├─► Check 1: Is the dotted path correct?
│   hooks.py: "myapp.events.sales.validate"
│   File:     myapp/events/sales.py → def validate(doc, method=None):
│   COMMON MISTAKE: "myapp.events.sales_invoice.validate" when file is sales.py
│
├─► Check 2: Is the dict structure correct?
│   doc_events uses NESTED dict: {"Sales Invoice": {"validate": "path"}}
│   scheduler_events uses LIST: {"daily": ["path1", "path2"]}
│   permission_query uses FLAT dict: {"Sales Invoice": "path"}
│
├─► Check 3: Is bench restarted after hooks.py change?
│   ALWAYS run: bench restart (or bench clear-cache for dev)
│
├─► Check 4: Is the DocType name exact?
│   "Sales Invoice" NOT "SalesInvoice" NOT "sales_invoice"
│   Use exact DocType name as shown in Frappe UI
│
└─► Check 5: Is the app installed on the site?
    bench --site mysite list-apps

Circular Import Errors

# ❌ CAUSES ImportError — circular dependency
# myapp/hooks.py imports from myapp.events
# myapp/events/sales.py imports from myapp.hooks

# ✅ CORRECT — break the cycle
# Move shared constants to myapp/constants.py
# Import from constants in both hooks.py and events/

**Rule**: NEVER import from hooks.py in your event handlers. hooks.py is read by the framework, not imported by your code.

Wrong Dict Structure by Hook Type

# ❌ WRONG — doc_events needs nested dict, not flat
doc_events = {
    "Sales Invoice": "myapp.events.validate"  # WRONG: string, not dict
}

# ✅ CORRECT
doc_events = {
    "Sales Invoice": {
        "validate": "myapp.events.sales.validate"
    }
}

# ❌ WRONG — scheduler_events daily needs list
scheduler_events = {
    "daily": "myapp.tasks.daily_sync"  # WRONG: string, not list
}

# ✅ CORRECT
scheduler_events = {
    "daily": ["myapp.tasks.daily_sync"]
}

# ❌ WRONG — cron needs nested dict with list values
scheduler_events = {
    "cron": ["0 9 * * *", "myapp.tasks.morning"]  # WRONG structure
}

# ✅ CORRECT
scheduler_events = {
    "cron": {
        "0 9 * * 1-5": ["myapp.tasks.morning_report"]
    }
}

---

app_include_js / app_include_css Errors

# ❌ WRONG — missing assets/ prefix
app_include_js = "js/myapp.js"

# ❌ WRONG — using Python module path instead of file path
app_include_js = "myapp.public.js.myapp"

# ✅ CORRECT — full asset path
app_include_js = "assets/myapp/js/myapp.js"

# ✅ CORRECT — multiple files as list
app_include_js = ["assets/myapp/js/app.js", "assets/myapp/js/utils.js"]
app_include_css = "assets/myapp/css/myapp.css"

**Diagnosis**: If JS/CSS not loading, check browser DevTools Network tab for 404. Run `bench build` after adding new files. ALWAYS verify the file exists at `myapp/public/js/myapp.js`.

---

scheduler_events Not Running

Diagnosis Steps

# Step 1: Is scheduler enabled?
bench scheduler status
# If disabled: bench scheduler enable

# Step 2: Are workers running?
bench doctor
# Look for: "Workers online: X"
# If 0: bench start (dev) or supervisorctl restart all (pro
Read more
Ships withfrappe-claude-skill-package

60 deterministic Claude AI skills for Frappe Framework & ERPNext v14-v16 development and operations

Get the whole plugin
Stats
178
Stars
53
Forks
Maintained
Maintenance
Python
Language
2mo ago
Last commit
8mo ago
Created
15d ago
Added

Repo: Impertio-Studio/Frappe_Claude_Skill_Package