Skip to main content

Error Handling

VEF separates transport-level HTTP behavior from business-level result codes, but both are ultimately returned through the same code / message / data response envelope.

Result Model Overview

VEF uses two closely related result types:

TypePurpose
result.Resultfinal response payload returned to clients
result.Errorstructured error object used inside application code

result.Result shape:

{
"code": 0,
"message": "Success",
"data": {}
}

Successful Responses

Successful handlers usually return:

return result.Ok(data).Response(ctx)

result.Ok(...) supports:

PatternMeaning
result.Ok()success without payload
result.Ok(data)success with payload
result.Ok(result.WithMessage(...))success with custom message
result.Ok(data, result.WithMessage(...))success with payload and custom message

Structured Error Creation

For business failures, handlers usually return:

return result.Err(
"user already exists",
result.WithCode(result.ErrCodeRecordAlreadyExists),
)

result.Err(...) supports:

PatternMeaning
result.Err()default business error
result.Err("message")business error with custom message
result.Err("message", result.WithCode(...))custom business code
result.Err("message", result.WithStatus(...))custom HTTP status
result.Err("message", result.WithCode(...), result.WithStatus(...))full override

result.Errf(...) provides the same idea with formatted messages.

Error Options

Available result options:

OptionApplies toEffect
result.WithCode(code)result.Err(...)sets the business error code
result.WithStatus(status)result.Err(...)sets the HTTP status code
result.WithMessage(message)result.Ok(...)overrides the success message
result.WithMessagef(format, ...)result.Ok(...)formats the success message

Predefined Error Families

VEF ships a large set of predefined errors in the result package.

Authentication errors

Error valueBusiness codeDefault HTTP status
result.ErrUnauthenticatedErrCodeUnauthenticated401
result.ErrTokenExpiredErrCodeTokenExpired401
result.ErrTokenInvalidErrCodeTokenInvalid401
result.ErrTokenNotValidYetErrCodeTokenNotValidYet401
result.ErrTokenInvalidIssuerErrCodeTokenInvalidIssuer401
result.ErrTokenInvalidAudienceErrCodeTokenInvalidAudience401
result.ErrTokenMissingSubjectErrCodeTokenMissingSubject401
result.ErrTokenMissingTokenTypeErrCodeTokenMissingTokenType401

Signature or external-app auth errors

Error valueBusiness codeDefault HTTP status
result.ErrAppIDRequiredErrCodeAppIDRequired401
result.ErrTimestampRequiredErrCodeTimestampRequired401
result.ErrSignatureRequiredErrCodeSignatureRequired401
result.ErrTimestampInvalidErrCodeTimestampInvalid401
result.ErrSignatureExpiredErrCodeSignatureExpired401
result.ErrSignatureInvalidErrCodeSignatureInvalid401
result.ErrExternalAppNotFoundErrCodeExternalAppNotFound401
result.ErrExternalAppDisabledErrCodeExternalAppDisabled401
result.ErrIPNotAllowedErrCodeIPNotAllowed401
result.ErrNonceRequiredErrCodeNonceRequired401
result.ErrNonceInvalidErrCodeNonceInvalid401
result.ErrNonceAlreadyUsedErrCodeNonceAlreadyUsed401
result.ErrAuthHeaderMissingErrCodeAuthHeaderMissing401
result.ErrAuthHeaderInvalidErrCodeAuthHeaderInvalid401

Challenge flow errors

Error valueBusiness codeDefault HTTP status
result.ErrChallengeTokenInvalidErrCodeChallengeTokenInvalid401
result.ErrChallengeTypeInvalidErrCodeChallengeTypeInvalid400
result.ErrOTPCodeRequiredErrCodeOTPCodeRequired400
result.ErrOTPCodeInvalidErrCodeOTPCodeInvalid401
result.ErrNewPasswordRequiredErrCodeNewPasswordRequired400
result.ErrDepartmentRequiredErrCodeDepartmentRequired400

Authorization and request errors

Error valueBusiness codeDefault HTTP status
result.ErrAccessDeniedErrCodeAccessDenied403
result.ErrTooManyRequestsErrCodeTooManyRequests429
result.ErrRequestTimeoutErrCodeRequestTimeout408
result.ErrUnknownErrCodeUnknown500

Business errors

Error valueBusiness codeDefault HTTP status
result.ErrRecordNotFoundErrCodeRecordNotFound200
result.ErrRecordAlreadyExistsErrCodeRecordAlreadyExists200
result.ErrForeignKeyViolationErrCodeForeignKeyViolation200
result.ErrDangerousSQLErrCodeDangerousSQL200

Error constructors

These helpers create structured errors with specific semantics:

ConstructorTypical output
result.ErrNotImplemented(message)501 Not Implemented
result.ErrCredentialsInvalid(message)401 Unauthorized with credentials-invalid business code
result.ErrPrincipalInvalid(message)401 Unauthorized with principal-invalid business code

Business Codes

Selected result code ranges:

RangeMeaning
0success
1000-1099authentication and challenge errors
1100-1199authorization errors
1200-1499resource, media type, and request errors
1500-1699not implemented and SQL-related errors
1900-1999unknown errors
2000+business errors

Fiber Error Mapping

The app layer maps selected fiber.Error values into structured result payloads.

Current built-in mappings:

Fiber HTTP statusResult codeMessage key
401ErrCodeUnauthenticatedErrMessageUnauthenticated
403ErrCodeAccessDeniedErrMessageAccessDenied
404ErrCodeNotFoundErrMessageNotFound
415ErrCodeUnsupportedMediaTypeErrMessageUnsupportedMediaType
408ErrCodeRequestTimeoutErrMessageRequestTimeout

If a fiber.Error status code is not mapped, VEF logs it and falls back to the generic unknown error result.

Error Resolution Order

At runtime, VEF resolves errors in this order:

  1. fiber.Error
  2. result.Error
  3. unknown or unwrapped error -> result.ErrUnknown

This is why returning explicit result.Error values is better than returning opaque errors for domain failures.

Practical Patterns

Success with payload

return result.Ok(user).Response(ctx)

Success with custom message

return result.Ok(
user,
result.WithMessage("user synced"),
).Response(ctx)

Business error with code

return result.Err(
"user already exists",
result.WithCode(result.ErrCodeRecordAlreadyExists),
)

Explicit HTTP status override

return result.Err(
"forbidden",
result.WithCode(result.ErrCodeAccessDenied),
result.WithStatus(fiber.StatusForbidden),
)

Practical Advice

  • think of result as the public response contract
  • use predefined result errors when they already match the scenario
  • use domain-specific business codes when the client must react differently
  • prefer structured result.Error values over ad hoc string errors for expected business failures
  • avoid manually writing raw JSON responses unless you are intentionally bypassing the result contract

Next Step

Read Authentication to see how auth failures flow into this result model.