guidewire-common-errors
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGuidewire Common Errors
Guidewire常见错误
Overview
概述
Diagnose and resolve the most common errors encountered in Guidewire InsuranceSuite Cloud API, Gosu development, and integrations.
诊断并解决Guidewire InsuranceSuite Cloud API、Gosu开发和集成中遇到的最常见错误。
Prerequisites
前提条件
- Access to Guidewire Cloud Console logs
- Understanding of HTTP status codes
- Familiarity with Gosu exception handling
- 拥有Guidewire Cloud Console日志的访问权限
- 了解HTTP状态码
- 熟悉Gosu异常处理
HTTP Status Code Reference
HTTP状态码参考
| Code | Meaning | Common Cause | Resolution |
|---|---|---|---|
| 400 | Bad Request | Malformed JSON, invalid field | Check request body structure |
| 401 | Unauthorized | Invalid/expired token | Refresh OAuth token |
| 403 | Forbidden | Missing API role | Check role assignments in GCC |
| 404 | Not Found | Invalid endpoint or ID | Verify URL and resource ID |
| 409 | Conflict | Concurrent modification | Retry with updated checksum |
| 422 | Unprocessable | Business rule violation | Fix validation errors |
| 429 | Too Many Requests | Rate limit exceeded | Implement backoff |
| 500 | Server Error | Internal error | Check server logs |
| 503 | Service Unavailable | Maintenance/overload | Retry with backoff |
| 状态码 | 含义 | 常见原因 | 解决方法 |
|---|---|---|---|
| 400 | 错误请求 | JSON格式错误、字段无效 | 检查请求体结构 |
| 401 | 未授权 | 令牌无效/过期 | 刷新OAuth令牌 |
| 403 | 禁止访问 | 缺少API角色 | 在GCC中检查角色分配 |
| 404 | 未找到 | 端点或ID无效 | 验证URL和资源ID |
| 409 | 冲突 | 并发修改 | 使用更新的校验和重试 |
| 422 | 无法处理 | 违反业务规则 | 修复验证错误 |
| 429 | 请求过多 | 超出速率限制 | 实现退避机制 |
| 500 | 服务器错误 | 内部错误 | 检查服务器日志 |
| 503 | 服务不可用 | 维护/过载 | 退避后重试 |
Cloud API Errors
Cloud API错误
401 Authentication Errors
401 认证错误
typescript
// Error: "invalid_token" or "expired_token"
// Solution: Implement token refresh
class TokenManager {
private token: string | null = null;
private expiry: Date | null = null;
async getValidToken(): Promise<string> {
if (this.isTokenValid()) {
return this.token!;
}
try {
const response = await this.refreshToken();
this.token = response.access_token;
// Set expiry 60 seconds before actual expiry for safety
this.expiry = new Date(Date.now() + (response.expires_in - 60) * 1000);
return this.token;
} catch (error) {
console.error('Token refresh failed:', error);
throw new AuthenticationError('Unable to obtain valid token');
}
}
private isTokenValid(): boolean {
return this.token !== null &&
this.expiry !== null &&
this.expiry > new Date();
}
}typescript
// Error: "invalid_token" or "expired_token"
// Solution: Implement token refresh
class TokenManager {
private token: string | null = null;
private expiry: Date | null = null;
async getValidToken(): Promise<string> {
if (this.isTokenValid()) {
return this.token!;
}
try {
const response = await this.refreshToken();
this.token = response.access_token;
// Set expiry 60 seconds before actual expiry for safety
this.expiry = new Date(Date.now() + (response.expires_in - 60) * 1000);
return this.token;
} catch (error) {
console.error('Token refresh failed:', error);
throw new AuthenticationError('Unable to obtain valid token');
}
}
private isTokenValid(): boolean {
return this.token !== null &&
this.expiry !== null &&
this.expiry > new Date();
}
}403 Permission Errors
403 权限错误
json
// Error response
{
"status": 403,
"error": "Forbidden",
"message": "Caller does not have permission to access endpoint: POST /account/v1/accounts",
"details": {
"requiredRole": "pc_account_admin",
"callerRoles": ["pc_policy_read"]
}
}Resolution:
- Log into Guidewire Cloud Console
- Navigate to Identity & Access > API Roles
- Find your service account
- Add the required API role ()
pc_account_admin - Wait 5 minutes for role propagation
json
// Error response
{
"status": 403,
"error": "Forbidden",
"message": "Caller does not have permission to access endpoint: POST /account/v1/accounts",
"details": {
"requiredRole": "pc_account_admin",
"callerRoles": ["pc_policy_read"]
}
}解决方法:
- 登录Guidewire Cloud Console
- 导航至“身份与访问 > API角色”
- 找到您的服务账号
- 添加所需的API角色()
pc_account_admin - 等待5分钟让角色生效
409 Conflict (Optimistic Locking)
409 冲突(乐观锁)
typescript
// Error: Checksum mismatch indicates concurrent modification
async function updateWithRetry<T>(
path: string,
getData: () => Promise<T>,
updateFn: (data: T) => Partial<T>,
maxRetries: number = 3
): Promise<T> {
let attempt = 0;
while (attempt < maxRetries) {
try {
// Get current state with checksum
const current = await client.request<{ data: T; checksum: string }>('GET', path);
// Apply update
const updated = {
data: {
attributes: updateFn(current.data),
checksum: current.checksum
}
};
return await client.request<T>('PATCH', path, updated);
} catch (error) {
if (error.response?.status === 409 && attempt < maxRetries - 1) {
attempt++;
console.log(`Conflict detected, retrying (${attempt}/${maxRetries})`);
await sleep(1000 * attempt); // Exponential backoff
continue;
}
throw error;
}
}
throw new Error('Max retries exceeded for optimistic locking conflict');
}typescript
// Error: Checksum mismatch indicates concurrent modification
async function updateWithRetry<T>(
path: string,
getData: () => Promise<T>,
updateFn: (data: T) => Partial<T>,
maxRetries: number = 3
): Promise<T> {
let attempt = 0;
while (attempt < maxRetries) {
try {
// Get current state with checksum
const current = await client.request<{ data: T; checksum: string }>('GET', path);
// Apply update
const updated = {
data: {
attributes: updateFn(current.data),
checksum: current.checksum
}
};
return await client.request<T>('PATCH', path, updated);
} catch (error) {
if (error.response?.status === 409 && attempt < maxRetries - 1) {
attempt++;
console.log(`Conflict detected, retrying (${attempt}/${maxRetries})`);
await sleep(1000 * attempt); // Exponential backoff
continue;
}
throw error;
}
}
throw new Error('Max retries exceeded for optimistic locking conflict');
}422 Validation Errors
422 验证错误
typescript
// Parse and display validation errors
interface ValidationErrorResponse {
status: 422;
error: 'Unprocessable Entity';
details: Array<{
field: string;
message: string;
code: string;
rejectedValue?: any;
}>;
}
function handleValidationError(error: ValidationErrorResponse): never {
console.error('Validation Errors:');
error.details.forEach(detail => {
console.error(` [${detail.code}] ${detail.field}: ${detail.message}`);
if (detail.rejectedValue !== undefined) {
console.error(` Rejected value: ${JSON.stringify(detail.rejectedValue)}`);
}
});
// Group by field for form display
const fieldErrors = error.details.reduce((acc, detail) => {
acc[detail.field] = acc[detail.field] || [];
acc[detail.field].push(detail.message);
return acc;
}, {} as Record<string, string[]>);
throw new ValidationError('Request validation failed', fieldErrors);
}Common Validation Error Codes:
| Code | Description | Example |
|---|---|---|
| Missing required field | |
| Wrong data format | |
| Value not in allowed set | |
| Value outside range | |
| Duplicate entity | |
| Invalid foreign key | |
typescript
// Parse and display validation errors
interface ValidationErrorResponse {
status: 422;
error: 'Unprocessable Entity';
details: Array<{
field: string;
message: string;
code: string;
rejectedValue?: any;
}>;
}
function handleValidationError(error: ValidationErrorResponse): never {
console.error('Validation Errors:');
error.details.forEach(detail => {
console.error(` [${detail.code}] ${detail.field}: ${detail.message}`);
if (detail.rejectedValue !== undefined) {
console.error(` Rejected value: ${JSON.stringify(detail.rejectedValue)}`);
}
});
// Group by field for form display
const fieldErrors = error.details.reduce((acc, detail) => {
acc[detail.field] = acc[detail.field] || [];
acc[detail.field].push(detail.message);
return acc;
}, {} as Record<string, string[]>);
throw new ValidationError('Request validation failed', fieldErrors);
}常见验证错误代码:
| 代码 | 描述 | 示例 |
|---|---|---|
| 缺少必填字段 | |
| 数据格式错误 | |
| 值不在允许范围内 | |
| 值超出范围 | |
| 实体重复 | |
| 外键无效 | |
Gosu Exceptions
Gosu异常
NullPointerException
NullPointerException
gosu
// Bad: Direct property access
var account = getAccount()
print(account.AccountNumber) // NPE if account is null
// Good: Null-safe access
var account = getAccount()
if (account != null) {
print(account.AccountNumber)
}
// Better: Elvis operator
var accountNumber = account?.AccountNumber ?: "Unknown"gosu
// Bad: Direct property access
var account = getAccount()
print(account.AccountNumber) // NPE if account is null
// Good: Null-safe access
var account = getAccount()
if (account != null) {
print(account.AccountNumber)
}
// Better: Elvis operator
var accountNumber = account?.AccountNumber ?: "Unknown"QueryException
QueryException
gosu
// Bad: Returns multiple rows unexpectedly
var account = Query.make(Account)
.compare(Account#AccountStatus, Equals, AccountStatus.TC_ACTIVE)
.select()
.AtMostOneRow // Throws if multiple results!
// Good: Handle multiple results explicitly
var accounts = Query.make(Account)
.compare(Account#AccountStatus, Equals, AccountStatus.TC_ACTIVE)
.select()
.toList()
if (accounts.Count > 1) {
LOG.warn("Multiple active accounts found, using first")
}
var account = accounts.first()gosu
// Bad: Returns multiple rows unexpectedly
var account = Query.make(Account)
.compare(Account#AccountStatus, Equals, AccountStatus.TC_ACTIVE)
.select()
.AtMostOneRow // Throws if multiple results!
// Good: Handle multiple results explicitly
var accounts = Query.make(Account)
.compare(Account#AccountStatus, Equals, AccountStatus.TC_ACTIVE)
.select()
.toList()
if (accounts.Count > 1) {
LOG.warn("Multiple active accounts found, using first")
}
var account = accounts.first()TransactionException
TransactionException
gosu
// Error: Entity from different bundle
function badUpdate(policy : Policy) {
Transaction.runWithNewBundle(\bundle -> {
// ERROR: policy is from outside bundle
policy.Status = PolicyStatus.TC_INFORCE // TransactionException!
})
}
// Good: Add entity to bundle first
function goodUpdate(policy : Policy) {
Transaction.runWithNewBundle(\bundle -> {
var p = bundle.add(policy) // Add to new bundle
p.Status = PolicyStatus.TC_INFORCE
})
}gosu
// Error: Entity from different bundle
function badUpdate(policy : Policy) {
Transaction.runWithNewBundle(\bundle -> {
// ERROR: policy is from outside bundle
policy.Status = PolicyStatus.TC_INFORCE // TransactionException!
})
}
// Good: Add entity to bundle first
function goodUpdate(policy : Policy) {
Transaction.runWithNewBundle(\bundle -> {
var p = bundle.add(policy) // Add to new bundle
p.Status = PolicyStatus.TC_INFORCE
})
}ValidationException
ValidationException
gosu
// Handle validation during commit
try {
Transaction.runWithNewBundle(\bundle -> {
var submission = createSubmission(bundle)
bundle.commit()
})
} catch (e : gw.api.database.ValidationException) {
LOG.error("Validation failed: ${e.Message}")
e.ValidationResult.Errors.each(\err -> {
LOG.error(" ${err.FieldPath}: ${err.Message}")
})
throw e
}gosu
// Handle validation during commit
try {
Transaction.runWithNewBundle(\bundle -> {
var submission = createSubmission(bundle)
bundle.commit()
})
} catch (e : gw.api.database.ValidationException) {
LOG.error("Validation failed: ${e.Message}")
e.ValidationResult.Errors.each(\err -> {
LOG.error(" ${err.FieldPath}: ${err.Message}")
})
throw e
}Integration Errors
集成错误
REST API Client Errors
REST API客户端错误
gosu
// Handle external service errors
uses gw.api.rest.FaultToleranceException
uses gw.api.rest.CircuitBreakerOpenException
class IntegrationService {
function callExternalService(request : Request) : Response {
try {
return _client.post("/api/resource", request)
} catch (e : CircuitBreakerOpenException) {
LOG.warn("Circuit breaker open, using fallback")
return getFallbackResponse()
} catch (e : FaultToleranceException) {
if (e.Cause typeis java.net.SocketTimeoutException) {
LOG.error("External service timeout")
throw new IntegrationTimeoutException("Service timed out", e)
}
LOG.error("Integration error: ${e.Message}")
throw new IntegrationException("External service error", e)
}
}
}gosu
// Handle external service errors
uses gw.api.rest.FaultToleranceException
uses gw.api.rest.CircuitBreakerOpenException
class IntegrationService {
function callExternalService(request : Request) : Response {
try {
return _client.post("/api/resource", request)
} catch (e : CircuitBreakerOpenException) {
LOG.warn("Circuit breaker open, using fallback")
return getFallbackResponse()
} catch (e : FaultToleranceException) {
if (e.Cause typeis java.net.SocketTimeoutException) {
LOG.error("External service timeout")
throw new IntegrationTimeoutException("Service timed out", e)
}
LOG.error("Integration error: ${e.Message}")
throw new IntegrationException("External service error", e)
}
}
}Message Queue Errors
消息队列错误
gosu
// Handle message delivery failures
uses gw.api.messaging.MessageTransport
class MessageHandler {
function handleDeliveryFailure(message : Message, error : Exception) {
var retryCount = message.RetryCount ?: 0
if (retryCount < 3) {
// Retry with exponential backoff
message.RetryCount = retryCount + 1
message.ScheduledSendTime = Date.Now.addMinutes(Math.pow(2, retryCount) as int)
message.Status = MessageStatus.TC_PENDING
LOG.info("Scheduling retry ${retryCount + 1} for message ${message.ID}")
} else {
// Move to dead letter queue
message.Status = MessageStatus.TC_ERROR
LOG.error("Message ${message.ID} failed after ${retryCount} retries: ${error.Message}")
notifySupport(message, error)
}
}
}gosu
// Handle message delivery failures
uses gw.api.messaging.MessageTransport
class MessageHandler {
function handleDeliveryFailure(message : Message, error : Exception) {
var retryCount = message.RetryCount ?: 0
if (retryCount < 3) {
// Retry with exponential backoff
message.RetryCount = retryCount + 1
message.ScheduledSendTime = Date.Now.addMinutes(Math.pow(2, retryCount) as int)
message.Status = MessageStatus.TC_PENDING
LOG.info("Scheduling retry ${retryCount + 1} for message ${message.ID}")
} else {
// Move to dead letter queue
message.Status = MessageStatus.TC_ERROR
LOG.error("Message ${message.ID} failed after ${retryCount} retries: ${error.Message}")
notifySupport(message, error)
}
}
}Database Errors
数据库错误
Deadlock Detection
死锁检测
gosu
// Handle database deadlocks
uses java.sql.SQLException
function executeWithDeadlockRetry<T>(operation() : T, maxRetries : int = 3) : T {
var attempt = 0
while (true) {
try {
return operation()
} catch (e : SQLException) {
if (isDeadlock(e) && attempt < maxRetries) {
attempt++
LOG.warn("Deadlock detected, retry ${attempt}/${maxRetries}")
Thread.sleep(100 * attempt) // Brief delay
continue
}
throw e
}
}
}
private function isDeadlock(e : SQLException) : boolean {
// Oracle: ORA-00060
// SQL Server: 1205
// PostgreSQL: 40P01
return e.ErrorCode == 60 ||
e.ErrorCode == 1205 ||
e.SQLState == "40P01"
}gosu
// Handle database deadlocks
uses java.sql.SQLException
function executeWithDeadlockRetry<T>(operation() : T, maxRetries : int = 3) : T {
var attempt = 0
while (true) {
try {
return operation()
} catch (e : SQLException) {
if (isDeadlock(e) && attempt < maxRetries) {
attempt++
LOG.warn("Deadlock detected, retry ${attempt}/${maxRetries}")
Thread.sleep(100 * attempt) // Brief delay
continue
}
throw e
}
}
}
private function isDeadlock(e : SQLException) : boolean {
// Oracle: ORA-00060
// SQL Server: 1205
// PostgreSQL: 40P01
return e.ErrorCode == 60 ||
e.ErrorCode == 1205 ||
e.SQLState == "40P01"
}Error Response Wrapper
错误响应包装器
typescript
// Standardized error handling wrapper
interface GuidewireError {
status: number;
code: string;
message: string;
details?: any;
traceId?: string;
}
class GuidewireApiError extends Error {
constructor(
public status: number,
public code: string,
message: string,
public details?: any,
public traceId?: string
) {
super(message);
this.name = 'GuidewireApiError';
}
static fromResponse(response: any): GuidewireApiError {
return new GuidewireApiError(
response.status,
response.error || 'UNKNOWN',
response.message || 'An error occurred',
response.details,
response.headers?.['x-gw-trace-id']
);
}
toUserMessage(): string {
switch (this.code) {
case 'invalid_token': return 'Your session has expired. Please log in again.';
case 'forbidden': return 'You do not have permission to perform this action.';
case 'not_found': return 'The requested resource was not found.';
case 'validation_error': return 'Please correct the errors in your submission.';
default: return 'An unexpected error occurred. Please try again.';
}
}
}typescript
// Standardized error handling wrapper
interface GuidewireError {
status: number;
code: string;
message: string;
details?: any;
traceId?: string;
}
class GuidewireApiError extends Error {
constructor(
public status: number,
public code: string,
message: string,
public details?: any,
public traceId?: string
) {
super(message);
this.name = 'GuidewireApiError';
}
static fromResponse(response: any): GuidewireApiError {
return new GuidewireApiError(
response.status,
response.error || 'UNKNOWN',
response.message || 'An error occurred',
response.details,
response.headers?.['x-gw-trace-id']
);
}
toUserMessage(): string {
switch (this.code) {
case 'invalid_token': return 'Your session has expired. Please log in again.';
case 'forbidden': return 'You do not have permission to perform this action.';
case 'not_found': return 'The requested resource was not found.';
case 'validation_error': return 'Please correct the errors in your submission.';
default: return 'An unexpected error occurred. Please try again.';
}
}
}Resources
资源
Next Steps
下一步
For debugging techniques, see .
guidewire-debug-bundle如需调试技术,请查看。
guidewire-debug-bundle