Skip to content
AI & Agents
Skill

/frappe-errors-serverscripts

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

From plugin
frappe-claude-skill-package
17861 skills
Install
$ npx -y skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-errors-serverscripts --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-serverscripts

Context 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

SKILL.md

frappe-errors-serverscripts.SKILL.md
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"

Server Script Errors — Diagnosis and Resolution

Cross-refs: `frappe-syntax-serverscripts` (syntax), `frappe-impl-serverscripts` (workflows), `frappe-errors-clientscripts` (client-side).

---

CRITICAL: Server Scripts Disabled by Default [v15+]

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 Diagnosis Flowchart

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 Table

| 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 |

---

The #1 Error: ImportError

**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)

Available Sandbox API (Complete Reference)

| 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**

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
13d ago
Added

Repo: Impertio-Studio/Frappe_Claude_Skill_Package