erpnext-errors-api

安装

npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package --skill erpnext-errors-api
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 Code Meaning When Frappe Uses 200 Success Normal response 400 Bad Request Validation error 403 Forbidden Permission denied 404 Not Found Document doesn't exist 417 Expectation Failed frappe.throw() called 500 Server Error Unhandled 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 File Contents patterns.md Detailed error handling patterns examples.md Complete working examples anti-patterns.md Common mistakes to avoid See Also erpnext-api-patterns - API implementation patterns erpnext-syntax-whitelisted - Whitelisted method syntax erpnext-errors-serverscripts - Server Script error handling

返回排行榜