Skip to main content
Not all transactions can be fully parsed. This page covers error handling strategies for wallet integrations.

Error categories

CategoryCauseRecommended action
Invalid transactionMalformed bytes, wrong encodingShow error, don’t allow signing
Wrong chainTransaction doesn’t match specified chainAsk user to verify chain selection
Unknown contractNo ABI, not a known protocolShow available info + warning
Parse failureBug or unsupported featureFall back to raw display
Service unavailableNetwork or service downRetry or fall back

gRPC error codes

The parser returns standard gRPC status codes:
resp, err := client.Parse(ctx, request)
if err != nil {
    status := status.Convert(err)
    switch status.Code() {
    case codes.InvalidArgument:
        // Transaction couldn't be decoded
        // Show: "Invalid transaction format"
    case codes.FailedPrecondition:
        // Missing required metadata or wrong chain
        // Show: "Transaction doesn't match selected chain"
    case codes.Internal:
        // Parser error (bug or unsupported feature)
        // Show raw transaction with warning
    case codes.Unavailable:
        // Service down
        // Retry with backoff
    }
}

Error code reference

CodeNameDescription
3INVALID_ARGUMENTInvalid transaction bytes or encoding
5NOT_FOUNDChain not supported
9FAILED_PRECONDITIONChain mismatch or missing required data
13INTERNALParser error
14UNAVAILABLEService temporarily unavailable

Graceful degradation

When parsing fails or returns incomplete data, you can still allow signing with appropriate warnings:
async function parseTransaction(rawTx: string, chain: Chain): Promise<ParseResult> {
    try {
        const result = await parser.parse(rawTx, chain);
        return {
            success: true,
            visualSign: result,
            warnings: []
        };
    } catch (error) {
        // Log for debugging
        console.error('Parse failed:', error);

        // Determine severity
        if (isInvalidTransaction(error)) {
            // Don't allow signing malformed transactions
            return {
                success: false,
                error: 'This transaction appears to be malformed and cannot be signed.',
                allowSigning: false
            };
        }

        // For other errors, allow signing with warning
        return {
            success: false,
            fallback: {
                title: 'Unknown Transaction',
                warning: 'Transaction details could not be fully parsed.',
                rawData: rawTx,
            },
            allowSigning: true  // User can proceed at their own risk
        };
    }
}

User communication

Match error severity to UI treatment:
ScenarioUI Treatment
Parsed successfullyShow VisualSign fields normally
Unknown contractShow parsed fields + “Interacting with unverified contract” banner
Partial parseShow what’s known + “Some details unavailable” notice
Parse failed entirelyShow raw hex + “Unable to decode transaction” warning
Invalid transactionError state, disable signing
Service unavailable”Checking transaction…” with retry option

Example warning banners

Unknown contract:
⚠️ Unverified Contract
This transaction interacts with a contract we don't recognize.
Review the raw data carefully before signing.
Service unavailable:
⚠️ Unable to Verify
We couldn't connect to the transaction parser.
[Retry] [Sign Anyway]

Retry logic

For transient failures, implement retry with exponential backoff:
func parseWithRetry(ctx context.Context, req *ParseRequest) (*ParseResponse, error) {
    var lastErr error
    for attempt := 0; attempt < 3; attempt++ {
        resp, err := client.Parse(ctx, req)
        if err == nil {
            return resp, nil
        }

        // Only retry on transient errors
        if status.Code(err) != codes.Unavailable {
            return nil, err
        }

        lastErr = err
        time.Sleep(time.Duration(attempt+1) * 100 * time.Millisecond)
    }
    return nil, lastErr
}

Health checks

Monitor parser availability before users need it:
# gRPC health check
grpcurl -plaintext localhost:44020 grpc.health.v1.Health/Check
// Programmatic health check
func checkParserHealth(ctx context.Context) bool {
    resp, err := healthClient.Check(ctx, &healthpb.HealthCheckRequest{
        Service: "parser.ParserService",
    })
    return err == nil && resp.Status == healthpb.HealthCheckResponse_SERVING
}

Logging and monitoring

Track parsing outcomes for debugging and improvement:
// Log parse attempts
log.Info("parse_attempt",
    "chain", req.Chain,
    "tx_size", len(req.UnsignedPayload),
    "has_metadata", req.ChainMetadata != nil,
)

// Log outcomes
if err != nil {
    log.Error("parse_failed",
        "error", err,
        "code", status.Code(err),
    )
    metrics.Counter("parser.failures").Inc()
} else {
    metrics.Counter("parser.successes").Inc()
}

Next steps