TrustWeave provides structured error handling with rich context for better debugging and error recovery.
Overview
Important: The TrustWeave facade is hybrid. Credential operations issue, verify, presentationResult, and batch flows return sealed result types, not exceptions, for the primary failure modes (including AdapterNotReady when misconfigured). Many DID APIs return DidCreationResult and related sealed types.
Sealed-result error handling (preferred for credentials):
Use exhaustive when on IssuanceResult, VerificationResult, PresentationResult
importorg.trustweave.did.exception.DidExceptionimportorg.trustweave.did.exception.DidException.DidMethodNotRegisteredimportorg.trustweave.did.exception.DidException.DidNotFoundimportorg.trustweave.did.exception.DidException.InvalidDidFormatimportorg.trustweave.testkit.services.*// Handle DID errors with short importstry{valdid=trustWeave.createDid{method(KEY)}}catch(error:DidException){when(error){isDidMethodNotRegistered->{println("Method not registered: ${error.method}")println("Available: ${error.availableMethods}")}isDidNotFound->{println("DID not found: ${error.did}")}isInvalidDidFormat->{println("Invalid format: ${error.reason}")}}}
Credential-Related Errors (in trustweave-credentials module)
importorg.trustweave.core.exception.SerializationExceptionimportorg.trustweave.core.exception.TrustWeaveExceptionSerializationException.InvalidJson(jsonString="{ invalid }",parseError="Expected ',' or '}'",position="line 1, column 10")SerializationException.EncodeFailed(element="{ large object }",reason="Circular reference detected")TrustWeaveException.DigestFailed(algorithm="SHA-256",reason="Algorithm not available")TrustWeaveException.EncodeFailed(operation="base58-encoding",reason="Invalid byte array")
Validation Errors
1
2
3
4
5
6
7
8
importorg.trustweave.core.exception.TrustWeaveException// Validation failedTrustWeaveException.ValidationFailed(field="issuer",reason="Invalid DID format",value="invalid-did")
importorg.trustweave.core.exception.TrustWeaveException// Invalid operationTrustWeaveException.InvalidOperation(code="INVALID_OPERATION",message="Operation not allowed in current state",context=mapOf("operation"to"createDid","state"to"stopped"),cause=null)// Invalid stateTrustWeaveException.InvalidState(code="INVALID_STATE",message="TrustWeave not initialized",context=emptyMap(),cause=null)// Resource not foundTrustWeaveException.NotFound(resource="did:key:z6Mk...",message="Resource not found: did:key:z6Mk...",context=emptyMap(),cause=null)// Unknown error (catch-all)TrustWeaveException.Unknown(code="UNKNOWN_ERROR",message="Unexpected error occurred",context=emptyMap(),cause=originalException)
Error Code Quick Reference
Quick lookup table for common error codes and their solutions:
Code
Error Type
Common Causes
Solutions
DID_NOT_FOUND
DidNotFound
DID not resolvable, method not registered, network issue
Check DID format, ensure method registered, verify network connectivity
DID_METHOD_NOT_REGISTERED
DidMethodNotRegistered
Method not in registry
Register the method on DidMethodRegistry / TrustWeave.build, or list names via trustWeave.configuration.didRegistry.getAllMethodNames()
INVALID_DID_FORMAT
InvalidDidFormat
DID doesn’t match did:<method>:<identifier> format
Check credential structure, ensure all required fields present
CREDENTIAL_ISSUANCE_FAILED
CredentialIssuanceFailed
Signing failed, key not found, DID resolution failed
Verify issuer DID is resolvable, check key exists in DID document
CHAIN_NOT_REGISTERED
ChainNotRegistered
Chain not registered in registry
Register a client on BlockchainAnchorRegistry / TrustWeave.build { anchor { ... } }, or list IDs via trustWeave.configuration.blockchainRegistry.getAllChainIds()
WALLET_CREATION_FAILED
WalletCreationFailed
Provider not found, configuration invalid, storage unavailable
result.fold(onFailure={error->logger.error("Error: ${error.message}")logger.debug("Error code: ${error.code}")logger.debug("Context: ${error.context}")// Use context for better error handlingwhen(error){isDidException.DidMethodNotRegistered->{logger.info("Available methods: ${error.availableMethods}")// Suggest alternatives to user}isBlockchainException.ChainNotRegistered->{logger.info("Available chains: ${error.availableChains}")// Suggest fallback chains}// ... handle other specific errors}})
Why: Error context contains valuable debugging information and alternative options.
Pitfall 3: Ignoring Warnings in Verification Results
Bad:
1
2
3
4
when(valv=trustWeave.verify(credential)){isVerificationResult.Valid->processCredential(credential)// ignores warnings on `v`isVerificationResult.Invalid->{}}
Good:
1
2
3
4
5
6
7
8
9
10
11
when(valv=trustWeave.verify(credential)){isVerificationResult.Valid->{if(v.warnings.isNotEmpty()){logger.warn("Credential verified with warnings: ${v.warnings}")}processCredential(v.credential)}isVerificationResult.Invalid->{logger.error("Invalid: ${v.allErrors.joinToString()}")}}
Why:VerificationResult.Valid carries warnings you should log or policy-check before treating the credential as fully trusted.
Pitfall 4: Not Validating Inputs Before Operations
Bad:
1
2
// No validation, may fail with cryptic errorvalresolution=trustWeave.resolveDid(userInputDid)
Good:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Validate before operationvalvalidation=DidValidator.validateFormat(userInputDid)if(!validation.isValid()){valerror=validationasValidationResult.InvalidreturnResult.failure(DidException.InvalidDidFormat(did=userInputDid,reason=error.message))}// Now safe to proceed — still handle Failure brancheswhen(valresolution=trustWeave.resolveDid(userInputDid)){isDidResolutionResult.Success->{/* use resolution.document */}isDidResolutionResult.Failure->{/* NotFound, MethodNotRegistered, … */}}
Why: Early validation improves messages; resolution returns a sealed DidResolutionResult you should handle explicitly.
Pitfall 5: Not Handling Specific Error Types
Bad:
1
2
3
4
5
6
result.fold(onFailure={error->// Generic handling loses specific error informationprintln("Something went wrong: ${error.message}")})
result.fold(onFailure={error->when(error){isDidException.DidMethodNotRegistered->{// Specific handling for method not registeredlogger.warn("Method not registered: ${error.method}")logger.info("Available methods: ${error.availableMethods}")// Register method or suggest alternatives}isDidException.InvalidDidFormat->{// Specific handling for invalid formatlogger.error("Invalid DID format: ${error.reason}")// Show format requirements to user}isCredentialException.CredentialInvalid->{// Specific handling for invalid credentiallogger.error("Credential invalid: ${error.reason}")logger.debug("Field: ${error.field}")// Fix credential or reject}else->{// Generic handling for unknown errorslogger.error("Unexpected error: ${error.message}",error)}}})
Why: Specific error types provide actionable information for recovery.
TrustWeave automatically converts exceptions to TrustWeaveException:
1
2
3
4
5
6
7
8
9
10
importorg.trustweave.core.toTrustWeaveExceptiontry{// Some operation that might throwvalresult=someOperation()}catch(e:Exception){valerror=e.toTrustWeaveException()println("Error code: ${error.code}")println("Context: ${error.context}")}
Result utilities and batching
Lower-level APIs may return Kotlin Result<T>. The org.trustweave.core.util module provides helpers such as Result.mapError (see source / tests). For the TrustWeave facade, prefer sealed results (DidCreationResult, IssuanceResult, DidResolutionResult, …) and when.
TrustWeave validates inputs before operations to catch errors early:
DID Validation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
importorg.trustweave.core.util.DidValidator// Validate DID formatvalvalidation=DidValidator.validateFormat("did:key:z6Mk...")if(!validation.isValid()){valerror=validationasValidationResult.Invalidprintln("Validation failed: ${error.message}")println("Field: ${error.field}")println("Value: ${error.value}")}// Validate DID methodvalavailableMethods=listOf("key","web")valmethodValidation=DidValidator.validateMethod("did:key:z6Mk...",availableMethods)if(!methodValidation.isValid()){println("Method not supported")}
importorg.trustweave.core.ChainIdValidator// Validate chain ID formatvalvalidation=ChainIdValidator.validateFormat("algorand:testnet")if(!validation.isValid()){println("Invalid chain ID format")}// Validate chain is registeredvalavailableChains=listOf("algorand:testnet","polygon:testnet")valregisteredValidation=ChainIdValidator.validateRegistered("ethereum:mainnet",availableChains)if(!registeredValidation.isValid()){println("Chain not registered")}
Best Practices
1. Always Handle Errors
1
2
3
4
5
6
7
8
// Bad: ignoring the sealed resultvaldr=trustWeave.createDid{}// Good: exhaustive handling (or getOrThrowDid() only where appropriate)when(valdr=trustWeave.createDid{}){isDidCreationResult.Success->{/* use dr.did */}isDidCreationResult.Failure->{/* log / map to client error */}}
The TrustWeave facade does not expose initialize() / start() / stop() for plugins. Registration and SPI discovery use PluginRegistry and related APIs; failures surface as PluginException (for example InitializationFailed).
1
2
3
4
5
6
7
importorg.trustweave.core.exception.PluginExceptiontry{// register or load a plugin-capable provider}catch(e:PluginException.InitializationFailed){println("Plugin ${e.pluginId} failed: ${e.reason}")}
There is no generic “swap DID method in the string and re-resolve” API—fallbacks are policy: use another resolver, another endpoint, or a cached document. Prefer DidResolutionResult.Failure branches to drive that logic.
Configure methods before createDid
Register DID methods in TrustWeave.build { did { ... } } (or on the underlying DidMethodRegistry) before calling createDid. Runtime “auto-registration” snippets are not part of the public facade.
Circuit breaker with Result
If you wrap facade calls into Result for resilience libraries, keep the boundary explicit:
importkotlinx.coroutines.TimeoutCancellationExceptionimportkotlinx.coroutines.withTimeoutimportorg.trustweave.core.exception.TrustWeaveExceptionsuspendfun<T>withTimeoutOrResult(timeoutMillis:Long,block:suspend()->T):Result<T>=try{Result.success(withTimeout(timeoutMillis){block()})}catch(e:TimeoutCancellationException){Result.failure(TrustWeaveException.Unknown(message="Operation timed out after ${timeoutMillis}ms",cause=e))}// Usage: wrap a suspend call (here: resolution returns DidResolutionResult, not Result)valresolutionResult=withTimeoutOrResult(5_000){trustWeave.resolveDid("did:web:example.com")}.getOrThrow()
Exception vs Sealed Result Patterns
For a detailed explanation of when to use exceptions vs sealed results, see Error Handling Patterns:
When to use exceptions (programming errors)
When to use sealed results (expected failures)
Decision matrix for choosing the right pattern
Best practices for each pattern
Related Documentation
Error Handling Patterns](error-handling-patterns.md) - Exceptions vs sealed results guide