Error handling Understanding partial failures, error codes, and retry strategies.
Partial success Both walletPositions and poolDetails support partial success. When you query multiple protocols in one request, each protocol resolves independently. Successful results appear in data , failures appear in errors .
This means a timeout from one protocol never blocks the response from another.
Partial failure response
Copy {
"data" : {
"walletPositions" : {
"data" : [
{
"protocol" : "morpho" ,
"walletAddress" : "0x742d35cc6634c0532925a3b8d4c9db96c4b4d8b6" ,
"chainId" : 1 ,
"vaultV2Positions" : [{ "..." : "..." }],
"marketPositions" : []
}
],
"errors" : [
{
"protocol" : "aave" ,
"chainId" : 1 ,
"walletAddress" : "0x742d35cc6634c0532925a3b8d4c9db96c4b4d8b6" ,
"error" : {
"code" : "PROTOCOL_ERROR" ,
"message" : "Chain not supported by Aave adapter" ,
"retryable" : false
}
}
]
}
}
}
Expand Tip
Always check both data and errors arrays. A successful response can contain both.
Error structure type ProtocolError {
protocol : String ! # Protocol that failed ( e .g . "aave" )
chainId : Int ! # Chain ID where the query was attempted
walletAddress : String ! # Wallet address that was queried
error : ErrorDetail ! # Structured error detail
}
type PoolProtocolError {
protocol : String !
chainId : Int !
poolAddress : String ! # Pool address that was queried
error : ErrorDetail !
}
type ErrorDetail {
code : String ! # Machine -readable error code
message : String ! # Human -readable description
retryable : Boolean ! # Whether the client should retry
} Error codes Code Description Retryable NETWORK_ERROR Upstream service is unreachable Yes VALIDATION_ERROR Invalid input parameters (bad address, unsupported chain) No TIMEOUT Request exceeded the time limit Yes PROTOCOL_ERROR Protocol adapter returned an error No UNKNOWN_ERROR Unexpected failure Yes
Best practices Retry strategy Check the retryable field before retrying. For retryable errors, use exponential backoff:
async function queryWithRetry(query, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const result = await fetch(endpoint, { method: "POST" , body: JSON.stringify({ query }) });
const json = await result.json();
const retryableErrors = json.data.walletPositions.errors
.filter(e => e.error.retryable);
if (retryableErrors.length === 0) return json;
// Wait with exponential backoff before retrying failed protocols
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt)));
}
}Handling partial data Process successful results immediately, even if some protocols failed:
const { data, errors } = result.data.walletPositions;
// Process successful results
for (const position of data) {
switch (position.__typename) {
case "MorphoWalletPositions" :
handleMorpho(position);
break ;
case "AaveWalletPositions" :
handleAave(position);
break ;
// ...
}
}
// Log or handle failures
for (const err of errors) {
console.warn(`${err.protocol} on chain ${err.chainId}: ${err.error.message}` );
}Common validation errors These errors are not retryable — fix the input before retrying:
Invalid wallet address : Must be a valid hex address (0x-prefixed, 42 characters)Unsupported chain : The protocol does not support the requested chain ID. See supported chains Unknown protocol : The protocol identifier is not recognized