frappe-agent-architect
Use when designing multi-app Frappe architectures, deciding whether to split functionality into separate apps, or implementing cross-app communication…
Use when debugging or preventing errors in Frappe Server Scripts. Prevents ImportError (the #1 error), NameError for restricted builtins, sandbox violations, doc_events not firing, wrong script type selection, SQL injection, permission denied in scheduled scripts, infinite
$ npx -y skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-errors-serverscripts --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/frappe-errors-serverscriptsContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when debugging or preventing errors in Frappe Server Scripts. Prevents ImportError (the #1 error), NameError for restricted builtins, sandbox violations, doc_events not firing, wrong script type selection, SQL injection, permission denied in scheduled scripts, infinite
name: frappe-errors-serverscripts description: > Use when debugging or preventing errors in Frappe Server Scripts. Prevents ImportError (the #1 error), NameError for restricted builtins, sandbox violations, doc_events not firing, wrong script type selection, SQL injection, permission denied in scheduled scripts, infinite loops, and API scripts not returning JSON. Covers error message mapping table. Keywords: server script error, ImportError, NameError, sandbox,, ImportError in server script, script not running, sandbox error, restricted function. restricted, frappe.throw, doc_events, scheduler, API script, SQL injection. license: MIT compatibility: "Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16." metadata: author: OpenAEC-Foundation version: "2.0"
Cross-refs: `frappe-syntax-serverscripts` (syntax), `frappe-impl-serverscripts` (workflows), `frappe-errors-clientscripts` (client-side).
---
Starting from Frappe v15, Server Scripts are **disabled by default**. You MUST enable them:
# In site_config.json
{ "server_script_enabled": 1 }On Frappe Cloud: Server Scripts are ONLY available on **private benches**, NOT on shared benches.
---
ERROR IN SERVER SCRIPT
│
├─► ImportError / NameError
│ ├─► "import json" → BLOCKED. Use frappe.parse_json()
│ ├─► "import datetime" → BLOCKED. Use frappe.utils
│ ├─► "import os/sys/subprocess" → BLOCKED. Security restriction
│ └─► "NameError: name 'dict' is not defined" → Some builtins restricted
│
├─► SyntaxError: not allowed
│ ├─► "try/except" → BLOCKED by RestrictedPython [v14-v15]
│ ├─► "raise ValueError" → BLOCKED. Use frappe.throw()
│ └─► "exec/eval" → BLOCKED. Security restriction
│
├─► Script runs but nothing happens
│ ├─► Wrong Script Type selected → Check Document Event vs API vs Scheduler
│ ├─► Wrong DocType selected → Verify exact DocType name
│ ├─► Wrong Event selected → Before Save ≠ After Save
│ └─► Script disabled → Check "Enabled" checkbox
│
├─► 403 Permission Denied
│ ├─► Scheduler script → Runs as Administrator, check role permissions
│ ├─► API script → Check Allow Guest setting
│ └─► doc_event → User lacks DocType permission
│
├─► Data not saved in Scheduler
│ └─► Missing frappe.db.commit() → REQUIRED in scheduler scripts
│
└─► API script returns empty/wrong response
└─► Not setting frappe.response["message"] → ALWAYS set response---
| Error Message | Cause | Fix | |---------------|-------|-----| | `ImportError: import not allowed` | Any `import` statement in sandbox | Use `frappe.utils`, `frappe.parse_json()`, etc. | | `NameError: name 'dict' is not defined` | Some Python builtins blocked by RestrictedPython | Use `frappe._dict()` or literal `{}` | | `SyntaxError: try/except not allowed` | RestrictedPython blocks exception handling [v14-v15] | Use conditional checks (`if/else`) instead | | `SyntaxError: raise not allowed` | RestrictedPython blocks `raise` | Use `frappe.throw()` | | `Script not executing` | Wrong Script Type or Event selected | Verify type matches: Document Event, API, or Scheduler | | `doc is not defined` | Using `doc` in API or Scheduler script (no document context) | `doc` is only available in Document Event scripts | | `PermissionError` in Scheduler | Scheduler runs as Administrator but script accesses restricted resource | Use `ignore_permissions=True` where appropriate | | `Changes not saved` in Scheduler | Missing `frappe.db.commit()` | ALWAYS call `frappe.db.commit()` in Scheduler scripts | | `API returns empty response` | Forgot to set `frappe.response["message"]` | ALWAYS set `frappe.response["message"] = result` | | `Timeout / killed` | Infinite loop or processing too many records | ALWAYS add `limit` to queries, ALWAYS use batch processing | | `ValidationError: qty is required` | `doc.save()` called in Before Save (recursion) | NEVER call `doc.save()` in Before Save; just set values | | `SQL injection via string format` | User input in SQL without escaping | ALWAYS use `frappe.db.escape()` or parameterized queries |
---
**Every beginner hits this.** The Server Script sandbox blocks ALL imports except `json`.
# ❌ BLOCKED — These ALL fail with ImportError
import json # Use frappe.parse_json() / frappe.as_json()
from datetime import datetime # Use frappe.utils.now(), frappe.utils.today()
import re # Not available in sandbox
import os # Security: blocked
import requests # Use frappe.make_get_request(), frappe.make_post_request()
# ✅ CORRECT — Sandbox equivalents
data = frappe.parse_json(doc.json_field) # Instead of json.loads()
today = frappe.utils.today() # Instead of datetime.date.today()
now = frappe.utils.now() # Instead of datetime.now()
diff = frappe.utils.date_diff(date1, date2) # Instead of timedelta
resp = frappe.make_get_request("https://api.com") # Instead of requests.get()
resp = frappe.make_post_request("https://api.com", data=payload)| Category | Available Methods | |----------|-------------------| | **Document** | `frappe.get_doc()`, `frappe.new_doc()`, `frappe.get_last_doc()`, `frappe.get_cached_doc()`, `frappe.get_mapped_doc()`, `frappe.rename_doc()`, `frappe.delete_doc()` | | **Database** | `frappe.db.get_list()`, `frappe.db.get_all()`, `frappe.db.get_value()`, `frappe.db.get_single_value()`, `frappe.db.set_value()`, `frappe.db.exists()`, `frappe.db.sql()`, `frappe.db.commit()`, `frappe.db.rollback()`, `frappe.db.escape()` | | **Query Builder** | `frappe.qb` (full query builder) | | **HTTP** | `frappe.make_get_request()`, `frappe.make_post_request()`, `frappe.make_put_request()` | | **Utility**
60 deterministic Claude AI skills for Frappe Framework & ERPNext v14-v16 development and operations
Repo: Impertio-Studio/Frappe_Claude_Skill_Package
Use when designing multi-app Frappe architectures, deciding whether to split functionality into separate apps, or implementing cross-app communication…
Use when debugging Frappe errors, using bench console for live inspection, analyzing tracebacks, or reading Frappe log files. Prevents wasted debugging time…
Use when receiving vague or unclear ERPNext/Frappe development requests that need interpretation. Transforms requirements like 'make invoice auto-calculate' or…
Use when migrating a Frappe app between major versions, detecting breaking API changes, or resolving post-migration errors. Prevents failed migrations from…
Use when reviewing or validating Frappe/ERPNext code against best practices and common pitfalls. Checks generated code before deployment, validates against all…
Use when building ERPNext/Frappe API integrations (v14/v15/v16) including REST API, RPC API, authentication, webhooks, and rate limiting. Covers external API…