guidewire-common-errors

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Guidewire 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状态码参考

CodeMeaningCommon CauseResolution
400Bad RequestMalformed JSON, invalid fieldCheck request body structure
401UnauthorizedInvalid/expired tokenRefresh OAuth token
403ForbiddenMissing API roleCheck role assignments in GCC
404Not FoundInvalid endpoint or IDVerify URL and resource ID
409ConflictConcurrent modificationRetry with updated checksum
422UnprocessableBusiness rule violationFix validation errors
429Too Many RequestsRate limit exceededImplement backoff
500Server ErrorInternal errorCheck server logs
503Service UnavailableMaintenance/overloadRetry 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:
  1. Log into Guidewire Cloud Console
  2. Navigate to Identity & Access > API Roles
  3. Find your service account
  4. Add the required API role (
    pc_account_admin
    )
  5. 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"]
  }
}
解决方法:
  1. 登录Guidewire Cloud Console
  2. 导航至“身份与访问 > API角色”
  3. 找到您的服务账号
  4. 添加所需的API角色(
    pc_account_admin
  5. 等待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:
CodeDescriptionExample
required
Missing required field
accountHolder is required
invalid_format
Wrong data format
dateOfBirth must be ISO date
invalid_value
Value not in allowed set
state.code 'XX' not valid
range_exceeded
Value outside range
premium exceeds policy limit
duplicate
Duplicate entity
Account number already exists
reference_not_found
Invalid foreign key
producerCode.id not found
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);
}
常见验证错误代码:
代码描述示例
required
缺少必填字段
accountHolder is required
invalid_format
数据格式错误
dateOfBirth must be ISO date
invalid_value
值不在允许范围内
state.code 'XX' not valid
range_exceeded
值超出范围
premium exceeds policy limit
duplicate
实体重复
Account number already exists
reference_not_found
外键无效
producerCode.id not found

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