erpnext-errors-api
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseERPNext API Error Handling
ERPNext API错误处理
Patterns for handling errors in API development. For syntax details, see .
erpnext-api-patternsVersion: v14/v15/v16 compatible
API开发中的错误处理模式。语法细节请参考。
erpnext-api-patterns版本:兼容v14/v15/v16
API Error Handling Overview
API错误处理概览
┌─────────────────────────────────────────────────────────────────────┐
│ 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 │
│ │
└─────────────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────────────┐
│ API 错误处理决策树 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 错误发生在哪个环节? │
│ │
│ 服务端(Python)? │
│ ├── 验证错误 → 使用frappe.throw()返回清晰提示信息 │
│ ├── 权限错误 → frappe.throw() + PermissionError异常 │
│ ├── 资源不存在 → frappe.throw() + DoesNotExistError异常 │
│ └── 意外错误 → 记录日志并向客户端返回通用错误信息 │
│ │
│ 客户端(JavaScript)? │
│ ├── frappe.call → 使用错误回调函数或.catch()方法 │
│ └── frappe.xcall → 结合async/await使用try/catch捕获异常 │
│ │
│ 外部集成场景? │
│ └── requests库 → 使用try/except捕获特定异常 │
│ │
└─────────────────────────────────────────────────────────────────────┘HTTP Status Codes Reference
HTTP状态码参考
| 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 |
| 状态码 | 含义 | Frappe使用场景 |
|---|---|---|
| 200 | 成功 | 正常响应 |
| 400 | 错误请求 | 验证失败 |
| 403 | 禁止访问 | 权限不足 |
| 404 | 未找到 | 文档不存在 |
| 417 | 预期失败 | 调用frappe.throw()时 |
| 500 | 服务器错误 | 未处理的异常 |
Server-Side Patterns
服务端处理模式
Basic Whitelisted Method
基础白名单方法
python
@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)python
@frappe.whitelist()
def update_status(docname, status):
# 验证输入
if not docname:
frappe.throw(_("文档名称为必填项"), frappe.ValidationError)
if status not in ["Draft", "Submitted", "Cancelled"]:
frappe.throw(_("无效状态:{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(_("文档{0}不存在").format(docname))
except frappe.PermissionError:
frappe.throw(_("权限不足"), frappe.PermissionError)Bulk Operation with Partial Failure
批量操作的部分失败处理
python
@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 resultspython
@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 resultsClient-Side Patterns
客户端处理模式
frappe.call Error Handling
frappe.call错误处理
javascript
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"
});
}
});javascript
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: __("更新成功"), indicator: "green"});
}
},
error: function(r) {
// HTTP错误或frappe.throw触发时调用
frappe.msgprint({
title: __("错误"),
message: r.message || __("操作失败"),
indicator: "red"
});
}
});async/await Pattern
async/await模式
javascript
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"));
}
}javascript
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(__("文档更新失败"));
}
}External API Pattern
外部API调用模式
python
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"))python
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("外部API超时", "API集成")
frappe.throw(_("外部服务超时,请稍后重试。"))
except requests.HTTPError as e:
frappe.log_error(f"HTTP {e.response.status_code}", "API集成")
frappe.throw(_("外部服务错误"))
except requests.RequestException as e:
frappe.log_error(str(e), "API集成")
frappe.throw(_("连接失败"))Critical Rules
核心规则
✅ ALWAYS
✅ 必须遵守
- Validate input before processing
- Use for user-facing errors
frappe.throw() - Log unexpected errors with
frappe.log_error() - Return structured responses from APIs
- Handle both success and error in callbacks
- 处理前先验证输入
- 面向用户的错误使用返回
frappe.throw() - 使用记录意外错误
frappe.log_error() - API返回结构化响应
- 回调中同时处理成功和错误场景
❌ NEVER
❌ 禁止操作
- Expose internal error details to users
- Catch exceptions without logging
- Return raw exception messages
- Assume API calls will succeed
- Skip input validation
- 向用户暴露内部错误细节
- 捕获异常但不记录日志
- 返回原始异常信息
- 假设API调用一定会成功
- 跳过输入验证
Quick Reference: Error Responses
错误响应速查
python
undefinedpython
undefinedUser-facing error (shows alert)
面向用户的错误(会显示弹窗提示)
frappe.throw(_("Clear error message"))
frappe.throw(_("清晰的错误提示"))
Permission error (403)
权限错误(返回403状态码)
frappe.throw(_("Not allowed"), frappe.PermissionError)
frappe.throw(_("无权限操作"), frappe.PermissionError)
Validation error (400)
验证错误(返回400状态码)
frappe.throw(_("Invalid input"), frappe.ValidationError)
frappe.throw(_("无效输入"), frappe.ValidationError)
Log error (no user message)
记录错误(不向用户返回提示)
frappe.log_error(frappe.get_traceback(), "Error Title")
---frappe.log_error(frappe.get_traceback(), "错误标题")
---Reference Files
参考文件
| File | Contents |
|---|---|
| patterns.md | Detailed error handling patterns |
| examples.md | Complete working examples |
| anti-patterns.md | Common mistakes to avoid |
| 文件 | 内容 |
|---|---|
| patterns.md | 详细的错误处理模式 |
| examples.md | 完整的可运行示例 |
| anti-patterns.md | 需要避免的常见错误 |
See Also
相关参考
- - API implementation patterns
erpnext-api-patterns - - Whitelisted method syntax
erpnext-syntax-whitelisted - - Server Script error handling
erpnext-errors-serverscripts
- - API实现模式
erpnext-api-patterns - - 白名单方法语法
erpnext-syntax-whitelisted - - 服务器脚本错误处理
erpnext-errors-serverscripts