Get the FREE Ultimate OpenClaw Setup Guide →

erpnext-errors-api

npx machina-cli add skill OpenAEC-Foundation/ERPNext_Anthropic_Claude_Development_Skill_Package/erpnext-errors-api --openclaw
Files (1)
SKILL.md
7.2 KB

ERPNext API Error Handling

Patterns for handling errors in API development. For syntax details, see erpnext-api-patterns.

Version: v14/v15/v16 compatible

API Error Handling Overview

┌─────────────────────────────────────────────────────────────────────┐
│ API ERROR HANDLING DECISION                                         │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│ Where is the error occurring?                                      │
│                                                                     │
│ Server-side (Python)?                                              │
│ ├── Validation error → frappe.throw() with clear message          │
│ ├── Permission error → frappe.throw() + PermissionError           │
│ ├── Not found        → frappe.throw() + DoesNotExistError         │
│ └── Unexpected       → Log + generic error to client              │
│                                                                     │
│ Client-side (JavaScript)?                                          │
│ ├── frappe.call      → Use error callback or .catch()             │
│ └── frappe.xcall     → Use try/catch with async/await             │
│                                                                     │
│ External integration?                                              │
│ └── requests library → try/except with specific exceptions         │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

HTTP Status Codes Reference

CodeMeaningWhen Frappe Uses
200SuccessNormal response
400Bad RequestValidation error
403ForbiddenPermission denied
404Not FoundDocument doesn't exist
417Expectation Failedfrappe.throw() called
500Server ErrorUnhandled exception

Server-Side Patterns

Basic Whitelisted Method

@frappe.whitelist()
def update_status(docname, status):
    # Validate input
    if not docname:
        frappe.throw(_("Document name is required"), frappe.ValidationError)
    
    if status not in ["Draft", "Submitted", "Cancelled"]:
        frappe.throw(_("Invalid status: {0}").format(status))
    
    try:
        doc = frappe.get_doc("My DocType", docname)
        doc.status = status
        doc.save()
        return {"success": True, "name": doc.name}
    except frappe.DoesNotExistError:
        frappe.throw(_("Document {0} not found").format(docname))
    except frappe.PermissionError:
        frappe.throw(_("Permission denied"), frappe.PermissionError)

Bulk Operation with Partial Failure

@frappe.whitelist()
def bulk_update(items):
    items = frappe.parse_json(items)
    results = {"success": [], "failed": []}
    
    for item in items:
        try:
            doc = frappe.get_doc("Item", item["name"])
            doc.update(item)
            doc.save()
            results["success"].append(item["name"])
        except Exception as e:
            results["failed"].append({
                "name": item["name"],
                "error": str(e)
            })
    
    frappe.db.commit()
    return results

Client-Side Patterns

frappe.call Error Handling

frappe.call({
    method: "myapp.api.update_status",
    args: { docname: "DOC-001", status: "Submitted" },
    callback: function(r) {
        if (r.message && r.message.success) {
            frappe.show_alert({message: __("Updated"), indicator: "green"});
        }
    },
    error: function(r) {
        // Called on HTTP error or frappe.throw
        frappe.msgprint({
            title: __("Error"),
            message: r.message || __("Operation failed"),
            indicator: "red"
        });
    }
});

async/await Pattern

async function updateDocument(docname, status) {
    try {
        const result = await frappe.xcall("myapp.api.update_status", {
            docname: docname,
            status: status
        });
        return result;
    } catch (error) {
        console.error("API Error:", error);
        frappe.throw(__("Failed to update document"));
    }
}

External API Pattern

import requests

def call_external_api(endpoint, data):
    try:
        response = requests.post(
            endpoint,
            json=data,
            timeout=30,
            headers={"Authorization": f"Bearer {get_api_key()}"}
        )
        response.raise_for_status()
        return response.json()
    except requests.Timeout:
        frappe.log_error("External API timeout", "API Integration")
        frappe.throw(_("External service timeout. Please try again."))
    except requests.HTTPError as e:
        frappe.log_error(f"HTTP {e.response.status_code}", "API Integration")
        frappe.throw(_("External service error"))
    except requests.RequestException as e:
        frappe.log_error(str(e), "API Integration")
        frappe.throw(_("Connection failed"))

Critical Rules

✅ ALWAYS

  • Validate input before processing
  • Use frappe.throw() for user-facing errors
  • Log unexpected errors with frappe.log_error()
  • Return structured responses from APIs
  • Handle both success and error in callbacks

❌ NEVER

  • Expose internal error details to users
  • Catch exceptions without logging
  • Return raw exception messages
  • Assume API calls will succeed
  • Skip input validation

Quick Reference: Error Responses

# User-facing error (shows alert)
frappe.throw(_("Clear error message"))

# Permission error (403)
frappe.throw(_("Not allowed"), frappe.PermissionError)

# Validation error (400)
frappe.throw(_("Invalid input"), frappe.ValidationError)

# Log error (no user message)
frappe.log_error(frappe.get_traceback(), "Error Title")

Reference Files

FileContents
patterns.mdDetailed error handling patterns
examples.mdComplete working examples
anti-patterns.mdCommon mistakes to avoid

See Also

  • erpnext-api-patterns - API implementation patterns
  • erpnext-syntax-whitelisted - Whitelisted method syntax
  • erpnext-errors-serverscripts - Server Script error handling

Source

git clone https://github.com/OpenAEC-Foundation/ERPNext_Anthropic_Claude_Development_Skill_Package/blob/main/skills/source/errors/erpnext-errors-api/SKILL.mdView on GitHub

Overview

Defines error handling patterns for ERPNext/Frappe API development across v14–v16. Covers server-side validation, permissions, and not-found errors, plus client-side frappe.call/xcall handling, and external/webhook integrations. Emphasizes consistent HTTP status signaling and clear messages.

How This Skill Works

On the server, errors use frappe.throw with specific error types (ValidationError, PermissionError, DoesNotExistError) and descriptive messages. Client-side calls use error callbacks or try/catch with async/await for frappe.call and frappe.xcall, while external integrations rely on Python requests with targeted exception handling. HTTP status codes map to outcomes such as 400, 403, 404, 417, and 500 to standardize responses.

When to Use It

  • Validating inputs and failing fast in server-side methods via whitelisted functions
  • Handling permission and not-found errors with appropriate frappe.throw and exception types
  • Processing bulk operations with per-item success and failure reporting
  • Implementing client-side error handling for frappe.call and frappe.xcall
  • Integrating with external APIs or webhooks using requests and corresponding HTTP status handling

Quick Start

  1. Step 1: Identify error points across server methods, client calls, and external integrations
  2. Step 2: Implement server-side error handling using specific exception types and clear messages
  3. Step 3: Add client-side error handling with frappe.call/xcall and standardize responses

Best Practices

  • Use precise exception types (ValidationError, PermissionError, DoesNotExistError) with clear messages
  • Validate inputs on the server side before database operations and fail fast
  • Return consistent error payloads and avoid leaking internal details
  • For bulk operations, accumulate per-item results and report partial failures
  • Log unexpected errors and surface user-friendly messages to clients; map to appropriate HTTP statuses

Example Use Cases

  • Server-side whitelisted method update_status validates inputs, handles missing doc, and returns success or descriptive errors
  • Bulk update processes a list of items, collecting successful updates and listing per-item failures with reasons
  • Client-side code using frappe.call handles errors via callback and checks r.message for success flags
  • External API integration uses requests with try/except to handle timeouts, auth errors, and non-200 responses
  • Webhook receiver validates payloads and uses appropriate error signaling to return 400 or 500 as needed

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers