Token导航 LogoToken导航

Agent Skill · 开发

frappe-errors-hooks(冰沙错误挂钩)

frappe-errors-hooks 用于记录任务执行中的错误、用户纠正、经验和能力缺口,适合在 Codex、Claude、Cursor、Gemini CLI 中希望让 Agent 持续沉淀问题、修正和最佳实践时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

frappe-errors-hooks 是开发类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为操作浏览器;许可证信息还不明确,第三方扫描已通过,按安装量在开发类的 21,746 个 Skill 里排第 15,404。

总安装 599周安装 24GitHub Stars 87下载 194核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:frappe-errors-hooks(冰沙错误挂钩)
来源仓库:https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package
仓库路径:skills/frappe-errors-hooks
安装命令:
npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package --skill frappe-errors-hooks
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package --skill frappe-errors-hooks

这个 Skill 是做什么的

开发类 Skill 面向写代码、改代码和排查问题,一般会读写仓库文件,部分还会执行构建或测试命令。

用于记录任务执行中的错误、用户纠正和经验缺口。frappe-errors-hooks 属于开发类 Skill,可作为该场景下的辅助能力补充。适合让 Agent 持续沉淀问题和修正最佳实践。可结合来源仓库和原始 README 核验具体用法。安装前建议确认权限范围和维护状态,避免触发不必要操作。

注意是否会触发联网、命令执行或文件读写,确保安全使用。

来源仓库内路径:skills/frappe-errors-hooks

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_de…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要操作浏览器,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

frappe-errors-hooks 怎么安装?

在终端执行 npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_development_…。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

frappe-errors-hooks 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

frappe-errors-hooks 需要什么权限?

权限级别是操作浏览器。该 Skill 可能涉及浏览器控制能力,使用时可能读取或操作网页内容,需要在受控环境中确认权限边界。

frappe-errors-hooks 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

frappe-errors-hooks 用的人多吗?

公开数据是累计安装 599 次,近一周安装 24 次,下载 194 次,GitHub 87 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

frappe-errors-hooks 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理开发类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

开发类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
skill-vetter

技能审查员 · OpenClaw

8,779,018986操作浏览器MIT-0通过
ontology

本体论 · OpenClaw

6,636,960576只读MIT-0通过
entra-app-registration

内部应用程序注册 · Codex、Claude

6,631,872764接触敏感数据未明确通过
entra-app-registration

内部应用程序注册 · Codex、Claude

3,757,680201接触敏感数据未明确通过
nano-banana-pro

纳米香蕉专业版 · OpenClaw

3,526,898364接触敏感数据MIT-0有提醒
frappe-errors-hooks

冰沙错误挂钩 · 本页

59987操作浏览器未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

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 / SymptomCauseFix
Hook not firing at allTypo in dotted pathVerify module path matches actual file location
ImportError on bench startWrong module path or circular importFix import path; break circular dependency
AttributeError: module has no attributeFunction name typo in hooks.pyMatch function name exactly to Python definition
app_include_js not loadingPath missing assets/ prefix or wrong extensionUse "assets/myapp/js/file.js" format
scheduler_events not runningScheduler disabled or workers downbench scheduler enable, check bench doctor
doc_events handler never calledDocType name misspelled in dict keyUse exact DocType name with spaces: "Sales Invoice"
permission_query_conditions breaks list viewSQL syntax error or frappe.throw() in handlerReturn valid SQL string; NEVER throw
override_doctype_class import failureParent class import path changed between versionsPin import to correct module path for target version
extend_doctype_class [v16+] method conflictTwo extensions define same method nameRename conflicting methods; check hook resolution order
Fixtures not loading on installWrong dt key or DocType doesn't exist on targetVerify DocType exists before export; check filter syntax
extend_bootinfo breaks loginUnhandled exception in boot handlerWrap ALL bootinfo code in try/except
Wildcard "*" handler breaks all savesUnhandled exception in wildcard doc_eventsALWAYS wrap wildcard handlers in try/except
Hook fires but changes lostMissing frappe.db.commit() in schedulerAdd explicit commit in scheduler/background tasks
Multiple handler chain brokenFirst handler throws, others never runIsolate 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 (prod)

# Step 3: Check Scheduled Job Log
# In Frappe UI: /api/method/frappe.client.get_list?doctype=Scheduled Job Log&limit=5

# Step 4: Check Error Log for task failures
# In Frappe UI: /app/error-log

# Step 5: Is the task registered?
bench execute frappe.utils.scheduler.get_all_tasks

Common Scheduler Failures

# ❌ PROBLEM: Task runs but changes not persisted
def daily_sync():
    for item in frappe.get_all("Item", limit=100):
        frappe.db.set_value("Item", item.name, "synced", 1)
    # MISSING: frappe.db.commit() — ALL changes lost!

# ✅ FIX: ALWAYS commit in scheduler tasks
def daily_sync():
    for item in frappe.get_all("Item", limit=100):
        frappe.db.set_value("Item", item.name, "synced", 1)
    frappe.db.commit()

# ❌ PROBLEM: Task fails silently — no debugging possible
def daily_task():
    try:
        process_records()
    except Exception:
        pass  # Silent death

# ✅ FIX: ALWAYS log errors in scheduler
def daily_task():
    try:
        process_records()
        frappe.db.commit()
    except Exception:
        frappe.log_error(frappe.get_traceback(), "Daily Task Error")

doc_events Errors

Error Handling by Event Phase

EventThrow EffectTransactionPattern
validatePrevents save, full rollbackPre-writeCollect errors, throw once
before_savePrevents save, full rollbackPre-writeSame as validate
on_updateDoc already saved, error shownPost-writeIsolate non-critical ops
after_insertDoc already saved, error shownPost-writeIsolate non-critical ops
on_submitDoc already submittedPost-writeIsolate non-critical ops
on_cancelDoc already cancelledPost-writeIsolate non-critical ops

Multiple Handler Chain Problem

# If App A and App B both register validate for Sales Invoice:
# App A's handler throws → App B's handler NEVER runs

# ✅ ALWAYS be aware: your handler is not alone
def validate(doc, method=None):
    """Collect errors, throw once at end."""
    errors = []
    if doc.grand_total < 0:
        errors.append(_("Total cannot be negative"))
    if errors:
        frappe.throw("<br>".join(errors))

# ✅ For on_update: isolate independent operations
def on_update(doc, method=None):
    try:
        send_notification(doc)
    except Exception:
        frappe.log_error(frappe.get_traceback(), f"Notify error: {doc.name}")
    try:
        sync_external(doc)
    except Exception:
        frappe.log_error(frappe.get_traceback(), f"Sync error: {doc.name}")

NEVER Commit in doc_events

# ❌ BREAKS transaction management
def on_update(doc, method=None):
    frappe.db.set_value("Counter", "main", "count", 100)
    frappe.db.commit()  # Partial commit — dangerous!

# ✅ Framework handles commits automatically
def on_update(doc, method=None):
    frappe.db.set_value("Counter", "main", "count", 100)

Permission Hook Errors

permission_query_conditions: NEVER Throw

# ❌ BREAKS list view entirely
def query_conditions(user):
    if "Sales User" not in frappe.get_roles(user):
        frappe.throw("Access denied")  # LIST VIEW CRASHES
    return f"owner = '{user}'"  # Also: SQL injection!

# ✅ CORRECT — safe fallback, escaped values
def query_conditions(user):
    try:
        user = user or frappe.session.user
        if "System Manager" in frappe.get_roles(user):
            return ""
        return f"`tabSales Invoice`.owner = {frappe.db.escape(user)}"
    except Exception:
        frappe.log_error(frappe.get_traceback(), "Query Conditions Error")
        return f"`tabSales Invoice`.owner = {frappe.db.escape(frappe.session.user)}"

Note: permission_query_conditions only affects frappe.db.get_list(), NOT frappe.db.get_all().

has_permission: NEVER Throw

# ❌ BREAKS document access
def has_permission(doc, user=None, permission_type=None):
    if doc.status == "Locked":
        frappe.throw("Locked")  # DOCUMENT INACCESSIBLE

# ✅ Return False to deny, None to defer
def has_permission(doc, user=None, permission_type=None):
    try:
        user = user or frappe.session.user
        if doc.status == "Locked" and permission_type == "write":
            return False
        return None  # Defer to default permission system
    except Exception:
        frappe.log_error(frappe.get_traceback(), "Permission Error")
        return None

Override & Extend Errors

override_doctype_class: Import Failures

# ❌ COMMON: Import path changes between ERPNext versions
# v14 path:
override_doctype_class = {
    "Sales Invoice": "myapp.overrides.CustomSI"
}
# myapp/overrides.py:
from erpnext.accounts.doctype.sales_invoice.sales_invoice import SalesInvoice
# This path may change in v15/v16!

# ✅ ALWAYS call super(), re-raise validation errors
class CustomSalesInvoice(SalesInvoice):
    def validate(self):
        try:
            super().validate()
        except frappe.ValidationError:
            raise  # ALWAYS re-raise validation errors
        except Exception:
            frappe.log_error(frappe.get_traceback(), "Parent validate error")
            raise
        self.custom_validation()

Warning: Only ONE app's override_doctype_class is active per DocType ("last writer wins"). Use extend_doctype_class [v16+] for multi-app compatibility.

extend_doctype_class [v16+]: Conflicts

# hooks.py
extend_doctype_class = {
    "Sales Invoice": ["myapp.extensions.si.SalesInvoiceMixin"]
}

# ❌ CONFLICT: Two extensions define same method
# App A: class Mixin: def custom_calc(self): ...
# App B: class Mixin: def custom_calc(self): ...
# Result: Last app's method wins silently

# ✅ ALWAYS prefix method names with app name
class SalesInvoiceMixin:
    def myapp_custom_calc(self):
        """Prefixed to avoid conflicts with other extensions."""
        pass

extend_bootinfo Errors

# ❌ BREAKS LOGIN — unhandled error prevents desk from loading
def extend_boot(bootinfo):
    settings = frappe.get_single("My Settings")  # DoesNotExistError!
    bootinfo.config = settings.config

# ✅ ALWAYS wrap in try/except with safe defaults
def extend_boot(bootinfo):
    bootinfo.myapp_config = {}
    try:
        if frappe.db.exists("My Settings", "My Settings"):
            settings = frappe.get_single("My Settings")
            bootinfo.myapp_config = {"feature": settings.feature or False}
    except Exception:
        frappe.log_error(frappe.get_traceback(), "Bootinfo Error")

Fixtures Not Loading

# ❌ WRONG — dt key misspelled
fixtures = [{"doctype": "Custom Field", "filters": [...]}]  # "doctype" not "dt"!

# ✅ CORRECT — use "dt" key
fixtures = [{"dt": "Custom Field", "filters": [["module", "=", "My App"]]}]

# ❌ PROBLEM: DocType doesn't exist on target site
fixtures = [{"dt": "My Custom DocType"}]  # If not created yet → install fails

# ✅ FIX: Ensure DocType is created before fixtures are imported
# Order: DocType JSON → fixtures JSON (install order matters)

Export command: bench --site mysite export-fixtures Import: Automatic during bench --site mysite install-app myapp


Critical Rules

ALWAYS

  1. Restart bench after changing hooks.py
  2. Use try/except in scheduler tasks — no user sees errors
  3. Call frappe.db.commit() in scheduler — no auto-commit
  4. Return safe fallbacks in permission hooks — NEVER throw
  5. Call super() in override classes — re-raise ValidationError
  6. Wrap extend_bootinfo in try/except — errors break login
  7. Wrap wildcard "*" doc_events in try/except — errors break ALL saves
  8. Prefix extend_doctype_class [v16+] methods with app name

NEVER

  1. Throw in permission_query_conditions — breaks list views
  2. Throw in has_permission — breaks document access
  3. Commit in doc_events — breaks transaction management
  4. Import from hooks.py in event handlers — causes circular imports
  5. Assume single handler — multiple apps register doc_events
  6. Use string formatting in permission SQL — SQL injection risk
  7. Ignore scheduler errors — they fail completely silently

Quick Reference: Error Handling by Hook Type

Hook TypeCan Throw?Commit?Error Strategy
doc_events (validate)YESNEVERCollect errors, throw once
doc_events (on_update+)CarefulNEVERIsolate non-critical ops
scheduler_eventsPointlessALWAYStry/except + log_error
permission_query_conditionsNEVERNEVERReturn "" or owner filter
has_permissionNEVERNEVERReturn None on error
extend_bootinfoNEVERNEVERtry/except + safe defaults
override_doctype_classYESNEVERsuper() + re-raise
extend_doctype_class [v16+]YESNEVERPrefix methods, avoid conflicts
fixturesN/AN/AVerify dt key and DocType existence
app_include_js/cssN/AN/ACheck assets/ prefix, run bench build

Reference Files

FileContents
references/patterns.mdComplete error handling patterns by hook type
references/examples.mdFull working examples with error handling
references/anti-patterns.mdCommon mistakes with wrong/correct pairs

See Also

  • frappe-syntax-hooks — Hook syntax and dict structures
  • frappe-impl-hooks — Implementation workflows
  • frappe-errors-controllers — Controller error handling
  • frappe-errors-database — Database error handling
  • frappe-errors-serverscripts — Server Script error handling

平台分布

Codex

39.01%
按下载量换算76

Claude

29.8%
按下载量换算58

Cursor

19.7%
按下载量换算38

Gemini CLI

9.42%
按下载量换算18

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

操作浏览器

该 Skill 可能涉及浏览器控制能力,使用时可能读取或操作网页内容,需要在受控环境中确认权限边界。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills