erpnext-code-validator

ERPNext Code Validator Agent

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "erpnext-code-validator" with this command: npx skills add openaec-foundation/erpnext_anthropic_claude_development_skill_package/openaec-foundation-erpnext-anthropic-claude-development-skill-package-erpnext-code-validator

ERPNext Code Validator Agent

This agent validates ERPNext/Frappe code against established patterns, common pitfalls, and version compatibility requirements.

Purpose: Catch errors BEFORE deployment, not after

When to Use This Agent

┌─────────────────────────────────────────────────────────────────────┐ │ CODE VALIDATION TRIGGERS │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ► Code has been generated and needs review │ │ "Check this Server Script before I save it" │ │ └── USE THIS AGENT │ │ │ │ ► Code is causing errors │ │ "Why isn't this working?" │ │ └── USE THIS AGENT │ │ │ │ ► Pre-deployment validation │ │ "Is this production-ready?" │ │ └── USE THIS AGENT │ │ │ │ ► Code review for best practices │ │ "Can this be improved?" │ │ └── USE THIS AGENT │ │ │ └─────────────────────────────────────────────────────────────────────┘

Validation Workflow

┌─────────────────────────────────────────────────────────────────────┐ │ CODE VALIDATOR WORKFLOW │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ STEP 1: IDENTIFY CODE TYPE │ │ ══════════════════════════ │ │ • Client Script (JavaScript) │ │ • Server Script (Python sandbox) │ │ • Controller (Python full) │ │ • hooks.py configuration │ │ • Jinja template │ │ • Whitelisted method │ │ │ │ STEP 2: RUN TYPE-SPECIFIC CHECKS │ │ ═════════════════════════════════ │ │ • Apply checklist for identified code type │ │ • Check syntax patterns │ │ • Verify API usage │ │ │ │ STEP 3: CHECK UNIVERSAL RULES │ │ ══════════════════════════════ │ │ • Error handling present │ │ • User feedback appropriate │ │ • Security considerations │ │ • Performance implications │ │ │ │ STEP 4: VERIFY VERSION COMPATIBILITY │ │ ════════════════════════════════════ │ │ • v14/v15/v16 specific features │ │ • Deprecated patterns │ │ • Version-specific behaviors │ │ │ │ STEP 5: GENERATE VALIDATION REPORT │ │ ══════════════════════════════════ │ │ • Critical errors (must fix) │ │ • Warnings (should fix) │ │ • Suggestions (nice to have) │ │ • Corrected code (if errors found) │ │ │ └─────────────────────────────────────────────────────────────────────┘

→ See references/workflow.md for detailed validation steps.

Critical Checks by Code Type

Server Script Checks

┌─────────────────────────────────────────────────────────────────────┐ │ ⚠️ SERVER SCRIPT CRITICAL CHECKS │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ [FATAL] Import statements │ │ ═══════════════════════════ │ │ ❌ import json → Use frappe.parse_json() │ │ ❌ from frappe.utils import X → Use frappe.utils.X() │ │ ❌ import requests → IMPOSSIBLE in Server Script │ │ │ │ [FATAL] Undefined variables │ │ ════════════════════════════ │ │ ❌ self.field → Use doc.field │ │ ❌ document.field → Use doc.field │ │ │ │ [FATAL] Wrong event handling │ │ ═══════════════════════════════ │ │ ❌ try/except for validation → Just frappe.throw() │ │ │ │ [ERROR] Event name mismatch │ │ ═══════════════════════════ │ │ ❌ Event "Before Save" code in "After Save" script │ │ │ │ [WARNING] Missing validation │ │ ═══════════════════════════════ │ │ ⚠️ No null/empty checks before operations │ │ │ └─────────────────────────────────────────────────────────────────────┘

Client Script Checks

┌─────────────────────────────────────────────────────────────────────┐ │ CLIENT SCRIPT CRITICAL CHECKS │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ [FATAL] Wrong API usage │ │ ═════════════════════════ │ │ ❌ frappe.db.get_value() → Server-side only! │ │ ❌ frappe.get_doc() → Server-side only! │ │ ✓ frappe.call() for server data │ │ │ │ [FATAL] Missing async handling │ │ ══════════════════════════════ │ │ ❌ let result = frappe.call() → Returns undefined │ │ ✓ frappe.call({callback: fn}) → Use callback │ │ ✓ await frappe.call({async:false}) → Or async/await │ │ │ │ [ERROR] Field refresh issues │ │ ════════════════════════════ │ │ ❌ frm.set_value() without refresh │ │ ✓ frm.set_value() then frm.refresh_field() │ │ │ │ [WARNING] Form state checks │ │ ═══════════════════════════ │ │ ⚠️ Not checking frm.doc.__islocal for new docs │ │ ⚠️ Not checking frm.doc.docstatus for submitted docs │ │ │ └─────────────────────────────────────────────────────────────────────┘

Controller Checks

┌─────────────────────────────────────────────────────────────────────┐ │ CONTROLLER CRITICAL CHECKS │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ [FATAL] Wrong lifecycle usage │ │ ═════════════════════════════ │ │ ❌ Modifying self.field in on_update → Changes NOT saved! │ │ ✓ Use frappe.db.set_value() in on_update │ │ │ │ [FATAL] Missing super() call │ │ ════════════════════════════ │ │ ❌ def validate(self): pass → Breaks parent validation │ │ ✓ def validate(self): super().validate() │ │ │ │ [ERROR] Transaction assumptions │ │ ═══════════════════════════════ │ │ ❌ Assuming rollback on error in on_update │ │ (only validate and before_* roll back on error) │ │ │ │ [ERROR] Circular save │ │ ══════════════════════ │ │ ❌ self.save() inside lifecycle hooks │ │ ❌ doc.save() for same document in hooks │ │ │ └─────────────────────────────────────────────────────────────────────┘

→ See references/checklists.md for complete checklists.

Validation Report Format

Code Validation Report

Code Type: [Server Script / Client Script / Controller / etc.]

Target DocType: [DocType name]

Event/Trigger: [Event name]


🔴 CRITICAL ERRORS (Must Fix)

LineIssueFix
3Import statement in Server ScriptUse frappe.utils.X() directly

🟡 WARNINGS (Should Fix)

LineIssueRecommendation
12No null check before .lower()Add: if value: value.lower()

🔵 SUGGESTIONS (Nice to Have)

LineSuggestion
8Consider using frappe.db.get_value for single field

Corrected Code

# [Corrected version with all critical errors fixed]

Version Compatibility

Version
Status

v14
✅ Compatible

v15
✅ Compatible

v16
✅ Compatible

## Universal Validation Rules

These apply to ALL code types:

### Security Checks

| Check | Severity | Description |
|-------|----------|-------------|
| SQL Injection | CRITICAL | Raw user input in SQL queries |
| Permission bypass | CRITICAL | Missing permission checks before operations |
| XSS vulnerability | HIGH | Unescaped user input in HTML |
| Sensitive data exposure | HIGH | Logging passwords/tokens |

### Error Handling Checks

| Check | Severity | Description |
|-------|----------|-------------|
| Silent failures | HIGH | Catching exceptions without handling |
| Missing user feedback | MEDIUM | Errors not communicated to user |
| Generic error messages | LOW | "An error occurred" without details |

### Performance Checks

| Check | Severity | Description |
|-------|----------|-------------|
| Query in loop | HIGH | frappe.db.* inside for loop |
| Unbounded query | MEDIUM | SELECT without LIMIT |
| Unnecessary get_doc | LOW | get_doc when get_value suffices |

→ See [references/examples.md](references/examples.md) for validation examples.

## Version-Specific Validations

### v16 Features (Fail on v14/v15)

```python
# These ONLY work on v16+
extend_doctype_class = {}  # hooks.py - v16 only
naming_rule = "UUID"       # DocType - v16 only
pdf_renderer = "chrome"    # Print Format - v16 only

Deprecated Patterns (Warn)

# DEPRECATED - still works but should update
frappe.bean()              # Use frappe.get_doc()
frappe.msgprint(raise_exception=True)  # Use frappe.throw()
job_name parameter         # Use job_id (v15+)

Version-Specific Behaviors

Behavior
v14
v15/v16

Scheduler tick
240s
60s

Background job dedup
job_name
job_id

Quick Validation Commands

Server Script Quick Check

- ❌ Any import
 statements? → FATAL

- ❌ Any self.
 references? → FATAL (use doc.
)

- ❌ Any try/except
? → WARNING (usually wrong)

- ✅ Uses frappe.throw()
 for validation errors? → GOOD

- ✅ Uses doc.field
 for document access? → GOOD

Client Script Quick Check

- ❌ Any frappe.db.*
 calls? → FATAL (server-side only)

- ❌ Any frappe.get_doc()
 calls? → FATAL (server-side only)

- ❌ frappe.call()
 without callback? → FATAL (async issue)

- ✅ Uses frm.doc.field
 for field access? → GOOD

- ✅ Uses frm.refresh_field()
 after changes? → GOOD

Controller Quick Check

- ❌ Modifying self.*
 in on_update
? → ERROR (won't save)

- ❌ Missing super().method()
 calls? → WARNING

- ❌ self.save()
 in lifecycle hook? → FATAL (circular)

- ✅ Imports at top of file? → GOOD (controllers allow imports)

- ✅ Error handling with try/except? → GOOD (controllers allow this)

Integration with Other Skills

This validator uses knowledge from:

Skill
What It Provides

erpnext-syntax-*

Correct syntax patterns

erpnext-impl-*

Correct implementation patterns

erpnext-errors-*

Error handling patterns

erpnext-database

Query patterns and pitfalls

erpnext-permissions

Permission check patterns

erpnext-api-patterns

API response patterns

Validation Depth Levels

Level
Checks
Use When

Quick
Fatal errors only
Initial scan

Standard
+ Warnings
Pre-deployment

Deep
+ Suggestions + Optimization
Production review

Default: Standard level for most validations.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

erpnext-code-interpreter

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

erpnext-syntax-jinja

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

erpnext-impl-controllers

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

erpnext-database

No summary provided by upstream source.

Repository SourceNeeds Review