| name | erpnext-errors-api |
| description | Error handling patterns for ERPNext/Frappe API development (v14/v15/v16). Covers whitelisted method errors, REST API errors, client-side handling, external integrations, and webhooks. Triggers: API error, whitelisted method error, frappe.call error, REST API error, webhook error, external API error, HTTP status codes. |
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):
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) {
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
frappe.throw(_("Clear error message"))
frappe.throw(_("Not allowed"), frappe.PermissionError)
frappe.throw(_("Invalid input"), frappe.ValidationError)
frappe.log_error(frappe.get_traceback(), "Error Title")
Reference Files
See Also
erpnext-api-patterns - API implementation patterns
erpnext-syntax-whitelisted - Whitelisted method syntax
erpnext-errors-serverscripts - Server Script error handling