solana_kit_errors
Structured errors for the Solana Kit SDK. Every failure in the SDK is a SolanaError carrying a numeric code from SolanaErrorCode and an optional context map, so callers can route on codes instead of parsing message strings.
This is the Dart port of @solana/errors from the Solana TypeScript SDK.
Installation
Install the package directly:
dependencies:
"solana_kit_errors": ^0.9.3
If your app uses several Solana Kit packages together, you can also depend on the umbrella package instead:
dart pub add solana_kit
Inside this monorepo, Dart workspace resolution uses the local package automatically.
Documentation
- Package page: https://pub.flutter-io.cn/packages/solana_kit_errors
- API reference: https://pub.flutter-io.cn/documentation/solana_kit_errors/latest/
- Workspace docs: https://openbudgetfun.github.io/solana_kit/
- Package catalog entry: https://openbudgetfun.github.io/solana_kit/reference/package-catalog#solana_kit_errors
- Source code: https://github.com/openbudgetfun/solana_kit/tree/main/packages/solana_kit_errors
For architecture notes, getting-started guides, and cross-package examples, start with the workspace docs site and then drill down into the package README and API reference.
Usage
Creating errors
SolanaError implements Exception, so it can be thrown and caught like any Dart exception. The context map is made unmodifiable at construction time.
import 'package:solana_kit_errors/solana_kit_errors.dart';
void main() {
// Simple error with no context.
final error = SolanaError(SolanaErrorCode.blockHeightExceeded);
print(error);
// Error with context variables interpolated into the message.
final notFoundError = SolanaError(
SolanaErrorCode.accountsAccountNotFound,
{'address': '11111111111111111111111111111111'},
);
print(notFoundError);
try {
throw SolanaError(SolanaErrorCode.transactionFeePayerMissing);
} on SolanaError catch (e) {
print('Code: ${e.code}');
print('Context: ${e.context}');
print('Message: $e');
}
}
Checking errors with isSolanaError
isSolanaError is a type guard. It checks whether a value is a SolanaError and optionally whether it matches a specific error code.
import 'package:solana_kit_errors/solana_kit_errors.dart';
void handleError(Object? error) {
// Check if it is any SolanaError.
if (isSolanaError(error)) {
print('Got a Solana error with code: ${(error as SolanaError).code}');
}
// Check for a specific error code.
if (isSolanaError(error, SolanaErrorCode.transactionFeePayerMissing)) {
print('Transaction is missing a fee payer!');
}
// Returns false for non-SolanaError values.
print(isSolanaError('not an error')); // false
print(isSolanaError(null)); // false
}
void main() {
handleError(SolanaError(SolanaErrorCode.transactionFeePayerMissing));
}
Error message interpolation
Error messages are templates with $variable placeholders filled from the context map. getErrorMessage performs the interpolation.
import 'package:solana_kit_errors/solana_kit_errors.dart';
void main() {
// Get an interpolated message directly.
final message = getErrorMessage(
SolanaErrorCode.addressesInvalidByteLength,
{'actualLength': 28},
);
print(message);
// Missing context values leave the placeholder as-is.
final partial = getErrorMessage(SolanaErrorCode.addressesInvalidByteLength);
print(partial);
// Codes without a message template produce a fallback message.
final unknown = getErrorMessage(SolanaErrorCode.blockHeightExceeded);
print(unknown);
}
Converting JSON-RPC errors
getSolanaErrorFromJsonRpcError converts a JSON-RPC error response into a SolanaError. Preflight failures automatically extract the nested transaction error.
import 'package:solana_kit_errors/solana_kit_errors.dart';
void main() {
// Typical JSON-RPC error response from a Solana node.
final rpcError = <String, Object?>{
'code': -32005,
'message': 'Node is unhealthy',
'data': <String, Object?>{},
};
final solanaError = getSolanaErrorFromJsonRpcError(rpcError);
print(solanaError.code == SolanaErrorCode.jsonRpcServerErrorNodeUnhealthy);
// Preflight failure errors automatically extract the nested transaction error.
final preflightError = <String, Object?>{
'code': -32002,
'message': 'Transaction simulation failed',
'data': <String, Object?>{
'err': 'BlockhashNotFound',
'logs': <String>[],
},
};
final preflightSolanaError = getSolanaErrorFromJsonRpcError(preflightError);
print(
preflightSolanaError.code ==
SolanaErrorCode.jsonRpcServerErrorSendTransactionPreflightFailure,
);
// The nested cause is available in the context.
final cause = preflightSolanaError.context['cause'] as SolanaError;
print(cause.code == SolanaErrorCode.transactionErrorBlockhashNotFound);
// Malformed responses produce a malformedJsonRpcError.
final malformed = getSolanaErrorFromJsonRpcError({'unexpected': 'data'});
print(malformed.code == SolanaErrorCode.malformedJsonRpcError);
}
Converting transaction and instruction errors
Transaction errors from RPC responses use a Rust enum-like format. getSolanaErrorFromTransactionError handles both string and map forms, and delegates InstructionError entries to getSolanaErrorFromInstructionError.
import 'package:solana_kit_errors/solana_kit_errors.dart';
void main() {
// Simple string error.
final error = getSolanaErrorFromTransactionError('BlockhashNotFound');
print(error.code == SolanaErrorCode.transactionErrorBlockhashNotFound);
// Error with nested context.
final rentError = getSolanaErrorFromTransactionError({
'InsufficientFundsForRent': {'account_index': 2},
});
print(rentError.code == SolanaErrorCode.transactionErrorInsufficientFundsForRent);
print(rentError.context['accountIndex']); // 2
// Instruction errors nested in transaction errors are delegated.
final txError = getSolanaErrorFromTransactionError({
'InstructionError': [0, 'InvalidAccountData'],
});
print(txError.code == SolanaErrorCode.instructionErrorInvalidAccountData);
// Custom program error with an error code.
final customError = getSolanaErrorFromInstructionError(1, {'Custom': 42});
print(customError.code == SolanaErrorCode.instructionErrorCustom);
print(customError.context['code']); // 42
print(customError.context['index']); // 1
}
Unwrapping simulation errors
When a transaction simulation fails, the actual error is wrapped in a simulation error. unwrapSimulationError gets at the underlying cause.
import 'package:solana_kit_errors/solana_kit_errors.dart';
void main() {
final simulationError = SolanaError(
SolanaErrorCode.jsonRpcServerErrorSendTransactionPreflightFailure,
{
'cause': SolanaError(SolanaErrorCode.transactionErrorBlockhashNotFound),
'logs': <String>[],
},
);
final underlying = unwrapSimulationError(simulationError);
print(underlying is SolanaError);
print(
(underlying! as SolanaError).code ==
SolanaErrorCode.transactionErrorBlockhashNotFound,
);
// Non-simulation errors are returned as-is.
final regularError = SolanaError(SolanaErrorCode.blockHeightExceeded);
print(identical(unwrapSimulationError(regularError), regularError));
}
Context encoding and decoding
encodeContextObject and decodeEncodedContext serialize error context maps to and from compact base64 strings, useful for transmitting error details.
import 'package:solana_kit_errors/solana_kit_errors.dart';
void main() {
final context = {
'address': '11111111111111111111111111111111',
'index': 0,
};
// Encode to a compact base64 string.
final encoded = encodeContextObject(context);
print(encoded);
// Decode back to the original map.
final decoded = decodeEncodedContext(encoded);
print(decoded['address']);
}
Typed Error Domains
solana_kit_errors includes domain helpers layered over numeric error codes. Use them to route error handling without hardcoding code ranges throughout your application.
import 'package:solana_kit_errors/solana_kit_errors.dart';
void handleSolanaFailure(SolanaError error) {
if (error.isInDomain(SolanaErrorDomain.rpc)) {
print('RPC failure: $error');
return;
}
if (error.isInDomain(SolanaErrorDomain.transaction)) {
print('Transaction failure: $error');
return;
}
print('Unhandled Solana error: $error');
}
This keeps your error-routing logic readable while still preserving the exact numeric code and context payload when you need lower-level diagnostics.
Preferred construction helpers
Use createSolanaError(...) and wrapSolanaError(...) when you want consistent null stripping, shared context keys, and nested-cause preservation.
import 'package:solana_kit_errors/solana_kit_errors.dart';
void main() {
final error = wrapSolanaError(
SolanaErrorCode.accountsFailedToDecodeAccount,
StateError('decoder failed'),
context: {
SolanaErrorContextKeys.address: '11111111111111111111111111111111',
SolanaErrorContextKeys.operation: 'decodeAccount',
},
);
print(error.context[SolanaErrorContextKeys.causeType]); // StateError
}
Prefer shared keys such as address, operation, methodName, path, statusCode, and url so diagnostics stay predictable across packages.
API Reference
Classes
SolanaError: core error class implementingException. Carries anint codeand an unmodifiableMap<String, Object?> context.SolanaErrorCode: abstract final class with 100+static const interror codes grouped by category (general, JSON-RPC, addresses, accounts, keys, instructions, instruction errors, signers, transactions, transaction errors, codecs, RPC, RPC subscriptions, program clients, invariant violations).RpcEnumErrorConfig: configuration class for mapping Solana RPC enum-style errors toSolanaErrorinstances.SolanaErrorContextKeys: shared key names for structured diagnostics such asaddress,operation,methodName,path,statusCode, and nested cause fields.SolanaErrorDomain: enum describing high-level error domains (for examplerpc,transaction,codecs,mobileWalletAdapter).
Functions
isSolanaError(Object? e, [int? code]): type guard that checks whether a value is aSolanaError, optionally matching a specific code.getSolanaErrorDomain(int code): classifies numeric error codes into typedSolanaErrorDomainvalues.isSolanaErrorCodeInDomain(int code, SolanaErrorDomain domain): checks if a numeric code belongs to a domain.isSolanaErrorInDomain(Object? error, SolanaErrorDomain domain): checks if anObject?is aSolanaErrorin a domain.getErrorMessage(int code, [Map<String, Object?> context]): returns the interpolated error message for a given error code and context.createSolanaError(int, {Map<String, Object?> context, Object? cause}): creates aSolanaErrorwith normalized context and optional nested cause details.wrapSolanaError(int, Object, {Map<String, Object?> context}): wraps an existing exception orSolanaErrorwhile preserving structured cause information.createSolanaErrorContext(Map<String, Object?>, {Object? cause}): normalizes context maps by dropping nulls and attaching consistent nested-cause metadata.getSolanaErrorFromJsonRpcError(Object?): converts a JSON-RPC error response map into aSolanaError.getSolanaErrorFromTransactionError(Object): converts a Solana RPC transaction error into aSolanaError.getSolanaErrorFromInstructionError(num index, Object): converts a Solana RPC instruction error into aSolanaError.getSolanaErrorFromRpcError(RpcEnumErrorConfig, Object): low-level converter for RPC enum-style errors.unwrapSimulationError(Object?): extracts the underlying cause from simulation-related errors.encodeContextObject(Map<String, Object?>): encodes a context map to a compact base64 string.decodeEncodedContext(String): decodes a base64-encoded context string back into a map.
Constants
solanaErrorMessages:Map<int, String>mapping everySolanaErrorCodeto its human-readable message template.
Example
Use example/main.dart as a runnable starting point for solana_kit_errors.
- Import path:
package:solana_kit_errors/solana_kit_errors.dart - This section is centrally maintained with
mdtto keep package guidance aligned. - After updating shared docs templates, run
docs:updatefrom the repo root.
Maintenance
- Validate docs in CI and locally with
docs:check. - Keep examples focused on one workflow and reference package README sections for deeper API details.
Libraries
- solana_kit_errors
- Structured error types and error-code utilities for the Solana Kit Dart SDK.