Proper error handling is crucial for Blinks as it provides users with clear feedback when something goes wrong. When an error occurs, the ActionError
object displays the error message directly in the Blink UI, preventing failed transactions and improving user experience.
Key Concepts
ActionError Object : Wrap error messages in ActionError
to display them in the Blink UI
Input Validation : Always validate user inputs before processing transactions
User-Friendly Messages : Provide clear, actionable error messages that help users understand what went wrong
HTTP Status Codes : Use appropriate status codes (400 for validation errors, 500 for server errors)
Best Practices
Input Validation Validate all inputs before expensive operations
User-Friendly Messages Use specific error messages that guide users to the solution
Graceful Error Handling Always catch and handle errors gracefully
Server-Side Logging Log errors server-side for debugging while showing user-friendly messages in the UI
Error Handling Example
Here’s how to implement input validation and error handling in our donation Blink example:
import {
ActionPostRequest ,
ActionPostResponse ,
ActionError ,
ACTIONS_CORS_HEADERS ,
} from "@solana/actions" ;
import { PublicKey } from "@solana/web3.js" ;
// Other code, such as headers, GET and OPTIONS request, etc.
export const POST = async ( req : Request ) => {
try {
const url = new URL ( req . url );
const amount = Number ( url . searchParams . get ( "amount" ));
// Validate donation amount
if ( ! amount || isNaN ( amount )) {
throw new Error ( "Please enter a valid donation amount" );
}
if ( amount < 0.05 ) {
throw new Error ( "Minimum donation is 0.05 SOL" );
}
if ( amount > 10 ) {
throw new Error ( "Maximum donation is 10 SOL per transaction" );
}
const request : ActionPostRequest = await req . json ();
// Nested validation example: Validate wallet address
let payer : PublicKey ;
try {
payer = new PublicKey ( request . account );
} catch {
throw new Error ( "Invalid wallet address format" );
}
// Process transaction (simplified for example)
const transaction = await prepareTransaction (
connection ,
payer ,
receiver ,
amount
);
const response : ActionPostResponse = {
type: "transaction" ,
transaction: Buffer . from ( transaction . serialize ()). toString ( "base64" ),
};
return Response . json ( response , {
status: 200 ,
headers
});
} catch ( error ) {
console . error ( "Donation error:" , error );
// Return ActionError for Blink UI display
const errorResponse : ActionError = {
message: error instanceof Error ? error . message : "Internal server error"
};
return new Response ( JSON . stringify ( errorResponse ), {
status: 500 ,
headers
});
}
};
// prepareTransaction function ...