Major Changes
-
#1157
64d52ebThanks @codama-releases! - Release Codama v2, supporting IDLs of the v2 standard. Upgrade v1 IDLs with thecodama upgradecommand or the@codama/upgradepackage. -
#1248
7f8bedaThanks @lorisleiva! - Carry node paths in error contexts. Every error about a node now exposes thepathof that node (aNodePathfrom the root when the thrower knows it, otherwise only the last node(s), e.g.[node]) instead of the node itself, its kind or its name. AddgetNodePathStringto render such paths as node selectors.import { getNodePathString } from '@codama/errors'; getNodePathString(e.context.path); // "[programNode]token.[accountNode]mint" getNodePathString([root]); // "[rootNode]"
BREAKING CHANGES
Node objects, kinds and names removed from error contexts. Node-related contexts drop fields such as
node,kind,nodeKind,linkNode,enum,program,account,instruction,pda,seed,parentand their redundant*Name/*Kindcompanions in favour of a singlepath. The last node ofpathis usually the node the error is about (each context documents where its path ends), and its ancestors are the nodes before it.if (isCodamaError(e, CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING)) { - const { accountName, instructionName } = e.context; + const account = e.context.path.at(-1); // instructionAccountNode + const instruction = e.context.path.at(-2); // instructionNode } if (isCodamaError(e, CODAMA_ERROR__UNEXPECTED_NODE_KIND)) { - const { expectedKinds, kind, node } = e.context; + const { expectedKinds, path } = e.context; // empty path when no node was found }Contexts that changed (codes are unchanged unless renamed, see the error codes changeset):
Code Removed Added UNEXPECTED_NODE_KIND(2)kind,nodepathLINKED_NODE_NOT_FOUND(4)kind,linkNode,namepathnow ends at the link nodeENUM_VARIANT_NOT_FOUND(9)enum,enumNamepathDISCRIMINATOR_FIELD_NOT_FOUND(10)path;fieldis now aPathStringDISCRIMINATOR_FIELD_HAS_NO_DEFAULT_VALUE(11)fieldpathVISITORS__CANNOT_ADD_DUPLICATED_PDA_NAMES(1200000)program,programNamepathVISITORS__INVALID_PDA_SEED_VALUES(1200001)instruction,instructionName,pdapathVISITORS__CYCLIC_DEPENDENCY_DETECTED_WHEN_RESOLVING_INSTRUCTION_DEFAULT_VALUES(1200002)instruction,instructionNamepath;cycleholdsstructFieldTypeNodes instead ofinstructionArgumentNodesVISITORS__CANNOT_USE_OPTIONAL_ACCOUNT_AS_PDA_SEED_VALUE(1200003)instruction,instructionName,instructionAccount,instructionAccountName,seed,seedNamepath(ends at the seed value)VISITORS__INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY(1200004)instruction,instructionName,parent,parentKind,parentNamepath,dependent(e.g.ownerorconfig.fee);dependencyKindis'accountValueNode' | 'dataValueNode'VISITORS__ACCOUNT_FIELD_NOT_FOUND(1200005)account,namepathVISITORS__INVALID_NUMBER_WRAPPER(1200006)kind,reason;wrapperis now the wrapper objectVISITORS__FAILED_TO_VALIDATE_NODE(1200008)validationItems[].nodevalidationItems[].causeVISITORS__INSTRUCTION_ENUM_DATA_FIELD_NOT_FOUND(1200009)argumentName,instruction,instructionNamepath,fieldNameVISITORS__CANNOT_FLATTEN_STRUCT_WITH_CONFLICTING_ATTRIBUTES(1200010)pathDYNAMIC_CLIENT__NODE_REFERENCE_NOT_FOUND(2500002)instructionNamepathDYNAMIC_CLIENT__ACCOUNT_MISSING(2500003)accountName,instructionNamepathDYNAMIC_CLIENT__INVALID_ACCOUNT_ADDRESS(2500004)accountNamepathDYNAMIC_CLIENT__ACCOUNT_RESOLVER_MISSING(2500007)accountNamepathDYNAMIC_CLIENT__UNSUPPORTED_OPTIONAL_ACCOUNT_STRATEGY(2500009)accountName,instructionNamepathDYNAMIC_CLIENT__FAILED_TO_DERIVE_PDA(2500010)accountNamepath(ends at the seed, or at the PDA for its program ID)DYNAMIC_CLIENT__DATA_MISSING(2500011)argumentName,instructionNamepath,pathString(e.g.config.fee)DYNAMIC_CLIENT__INVALID_ACCOUNT_INPUT(2500013)argumentNamepathDYNAMIC_CLIENT__UNEXPECTED_VALUE_TYPE(2500014)nodeKindpath(the node that rejected the value)DYNAMIC_CLIENT__FAILED_TO_ENCODE_DATA(2500015)argumentName,instructionNamepathDYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER(2500016)targetKind,targetNamepathDYNAMIC_CLIENT__UNSUPPORTED_NODE(2500018)nodeKindpathRENDERERS__UNSUPPORTED_NODE(2800000)kind,nodepathpathalways means a node path. In every context,pathis aNodePath. Path expressions (e.g.config.fees[0]) live underpathStringinstead (CANNOT_RESOLVE_PATH,DYNAMIC_CLIENT__DATA_MISSING,VISITORS__INSTRUCTION_DATA_FIELD_NOT_FOUND), orfieldfor discriminators. Identifier fields that remain (e.g.variant,missingField,pdaName) are typedIdentifierStringinstead ofCamelCaseString.Messages render node paths. Error messages render
$pathwithgetNodePathString(root omitted, an empty path renders asnone) and many message texts changed accordingly, e.g.Missing account [mint] in [transfer] instruction.becomesMissing account [programNode]token.[instructionNode]transfer.[instructionAccountNode]mint.. Production-encoded contexts encodepathas that same string, since nodes cannot be encoded, so decoded production contexts hold a string rather than nodes. Update any code matching on message texts. -
#1264
909960fThanks @lorisleiva! - Trim public exports that were only meant for internal use, so the public API only exposes what consumers need.BREAKING CHANGES
@codama/errorsno longer exportssafeCaptureStackTrace. It was unused, even byCodamaError, and is also gone fromcodama, which re-exports it. CallError.captureStackTracedirectly if you need it.@codama/fragments/javascriptno longer exportspreferIncoming. UsemergeImportMapsoraddToImportMap, which apply the same conflict-resolution rule.@codama/dynamic-address-resolutionno longer exportsOPTIONAL_NODE_KINDS. Check the type node kind directly, e.g.isNode(type, ['optionTypeNode', 'remainderOptionTypeNode', 'zeroableOptionTypeNode']).@codama/nodes-from-anchoronly exports its root and program converters. The per-node converters, their options types and the generics helpers are now internal. Convert whole IDLs withrootNodeFromAnchor(orrootNodeFromAnchorV00,rootNodeFromAnchorV01,programNodeFromAnchorV00andprogramNodeFromAnchorV01) and pick the nodes you need from the result. The removed exports are:accountNodeFromAnchorV00,arrayTypeNodeFromAnchorV00,constantNodeFromAnchorV00,definedTypeNodeFromAnchorV00,enumTypeNodeFromAnchorV00,enumVariantTypeNodeFromAnchorV00,errorNodeFromAnchorV00,eventNodeFromAnchorV00,instructionAccountNodeFromAnchorV00,instructionAccountNodesFromAnchorV00,instructionNodeFromAnchorV00,mapTypeNodeFromAnchorV00,optionTypeNodeFromAnchorV00,pdaNodeFromAnchorV00,pdaSeedTypeNodeFromAnchorV00,setTypeNodeFromAnchorV00,structFieldTypeNodeFromAnchorV00,structTypeNodeFromAnchorV00,tupleTypeNodeFromAnchorV00,typeNodeFromAnchorV00andInstructionAccountNodeFromAnchorV00Options.accountNodeFromAnchorV01,arrayTypeNodeFromAnchorV01,constantNodeFromAnchorV01,definedTypeNodeFromAnchorV01,enumTypeNodeFromAnchorV01,enumVariantTypeNodeFromAnchorV01,errorNodeFromAnchorV01,eventNodeFromAnchorV01,instructionAccountNodeFromAnchorV01,instructionAccountNodesFromAnchorV01,instructionNodeFromAnchorV01,optionTypeNodeFromAnchorV01,pdaSeedNodeFromAnchorV01,structFieldTypeNodeFromAnchorV01,structTypeNodeFromAnchorV01,tupleTypeNodeFromAnchorV01,typeNodeFromAnchorV01,unwrapGenericTypeFromAnchorV01,extractGenerics,GenericsV01,InstructionAccountNodeFromAnchorV01OptionsandPdaSeedNodeFromAnchorV01Options.extractPdasFromProgram: useextractPdasVisitorinstead.
- import { accountNodeFromAnchorV01 } from '@codama/nodes-from-anchor'; - const account = accountNodeFromAnchorV01(idl.accounts[0], idl.types, generics); + import { rootNodeFromAnchor } from '@codama/nodes-from-anchor'; + const account = rootNodeFromAnchor(idl).program.accounts?.[0];
@codama/visitors-coreno longer exportsLINKABLE_NODES,getDependenciesandassertNodePathHasProgram. These are also gone from@codama/visitorsandcodama, which re-export it. UsefindProgramNodeFromPathto check that a path has a program, andgetResolvedInstructionInputsVisitorto resolve instruction input dependencies. -
#1261
bb09077Thanks @lorisleiva! - Carry node paths in the remaining error contexts. Contexts that still held nodes or account names now hold node paths instead, e.g. thecycleof a circular dependency lists the path of each account and data field it goes through. Production-encoded contexts encode lists of node paths as lists of node selectors.getInstructionDataFieldsnow returns thefieldPathof each field, andmapVisitorgives the visited node to its map function.BREAKING CHANGES
Nodes and account names replaced by node paths in error contexts. The following contexts changed, completing the move to node paths.
if (isCodamaError(e, CODAMA_ERROR__DYNAMIC_CLIENT__CIRCULAR_ACCOUNT_DEPENDENCY)) { - const { chain } = e.context; // "a -> b -> a" + const { cycle, formattedCycle, path } = e.context; // formattedCycle: "a -> b -> a" + const account = cycle[0].at(-1); // instructionAccountNode a } if (isCodamaError(e, CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE)) { - const { accountName } = e.context; + const account = e.context.path.at(-1); // e.g. instructionAccountNode }Code Removed Added VISITORS__CYCLIC_DEPENDENCY_DETECTED_WHEN_RESOLVING_INSTRUCTION_DEFAULT_VALUES(1200002)cycleholds the path of each account and data field instead of the nodes themselvesVISITORS__INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY(1200004)dependencyuse dependencyKindanddependencyNameVISITORS__INVALID_NUMBER_WRAPPER(1200006)pathof the number to wrap (empty when the wrapper is invalid on its own)VISITORS__FAILED_TO_VALIDATE_NODE(1200008)pathof the validated nodeDYNAMIC_CLIENT__INSTRUCTION_NOT_FOUND(2500000)pathof the programDYNAMIC_CLIENT__PDA_NOT_FOUND(2500001)pathof the programDYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE(2500005)accountNamepathof the account, remaining accounts, PDA or data field, and theindexof the remaining account at faultDYNAMIC_CLIENT__CIRCULAR_ACCOUNT_DEPENDENCY(2500008)chainpathof the instruction,cycle,formattedCycletoAddressOrThrowtakes a node path. The second argument oftoAddressOrThrowfrom@codama/dynamic-address-resolutionis now the path of the node the value should be the address of, rather than an account name.- toAddressOrThrow(value, 'mint'); + toAddressOrThrow(value, [root, program, instruction, mint]);
It also takes an optional
indexfor values given in a list, e.g.toAddressOrThrow(value, [root, program, instruction, signers], 1), which the error carries in its context (it is not rendered in the message).Messages changed accordingly. The messages of these errors now render their
path, e.g.Circular dependency detected: [a -> b -> a].becomesCircular dependency detected when resolving the accounts and data of instruction [programNode]token.[instructionNode]transfer. Got the following dependency cycle [a -> b -> a].. -
#1260
3ad402aThanks @lorisleiva! - Require Node.js 22.12.0 or later.BREAKING CHANGES
Node.js 20 is no longer supported. Every package now declares
"engines": { "node": ">=22.12.0" }, the first Node.js 22 release that supportsrequire(esm)by default. Node.js 20 reached its end of life in April 2026, and some dependencies (e.g.commander) already require Node.js 22.12.0. -
#1248
7f8bedaThanks @lorisleiva! - Add, rename and remove error codes for Codama v2. Renamed codes keep their number, and removed codes are never reused.New codes:
CODAMA_ERROR__INVALID_BRANDED_STRING(13):{ actual, expected }.CODAMA_ERROR__INJECTED_VALUE_NOT_PROVIDED(14):{ key, path }.CODAMA_ERROR__CANNOT_RESOLVE_PATH(15):{ path, pathString, segment }.CODAMA_ERROR__NODE_PATH_PROGRAM_MISSING(16):{ path }.CODAMA_ERROR__DEFINED_TYPE_HAS_NO_FINITE_VALUE(17):{ path }.CODAMA_ERROR__INVALID_TICKS_PER_SECOND(18):{ path, ticksPerSecond }.CODAMA_ERROR__INVALID_INTERPOLATED_INTENT_PLACEHOLDER(19):{ placeholder, template }.CODAMA_ERROR__VISITORS__INVALID_PROVIDED_VALUE(1200013):{ expectedKinds, path }.CODAMA_ERROR__VISITORS__CANNOT_FLATTEN_STRUCT_WITH_PLUGINS(1200014):{ path }.CODAMA_ERROR__VISITORS__UNRECOGNIZED_UPDATE_KEYS(1200015):{ allowedKeys, selector, unrecognizedKeys }.CODAMA_ERROR__VISITORS__INSTRUCTION_DATA_FIELD_NOT_FOUND(1200016):{ path, pathString }.CODAMA_ERROR__VISITORS__INSTRUCTION_ACCOUNT_NOT_FOUND(1200017):{ accountName, path }.CODAMA_ERROR__VISITORS__DEFINED_TYPE_MEMBER_NOT_FOUND(1200018):{ missingMember, path }.CODAMA_ERROR__VISITORS__CANNOT_SET_INSTRUCTION_DISCRIMINATOR(1200019):{ path, reason }.CODAMA_ERROR__DYNAMIC_CLIENT__PDA_SEED_MISSING(2500020):{ path }.CODAMA_ERROR__DYNAMIC_CLIENT__DUPLICATE_SET_ITEM(2500021):{ firstIndex, index, path }.
BREAKING CHANGES
Renamed error codes. Codama v2 replaces instruction arguments with instruction data, so the codes referring to arguments are renamed after what they now cover (data, account inputs such as remaining accounts, or any value). Their numbers are unchanged.
Before After Code CODAMA_ERROR__VISITORS__INSTRUCTION_ENUM_ARGUMENT_NOT_FOUNDCODAMA_ERROR__VISITORS__INSTRUCTION_ENUM_DATA_FIELD_NOT_FOUND1200009 CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSINGCODAMA_ERROR__DYNAMIC_CLIENT__DATA_MISSING2500011 CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ARGUMENT_INPUTCODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ACCOUNT_INPUT2500013 CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPECODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_VALUE_TYPE2500014 CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_ARGUMENTCODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_DATA2500015 - import { CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING } from '@codama/errors'; + import { CODAMA_ERROR__DYNAMIC_CLIENT__DATA_MISSING } from '@codama/errors';
Removed error codes. The following codes are not thrown by any Codama v2 package and are removed. Their numbers will not be reused.
CODAMA_ERROR__UNEXPECTED_NESTED_NODE_KIND(3): nested type nodes no longer exist since type wrappers became transforms.CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING(2100003).CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED(2100005).CODAMA_ERROR__DYNAMIC_CLIENT__DEFAULT_VALUE_MISSING(2500012).
Deprecated resolver error codes.
CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_RESOLVER_MISSING(2500007) andCODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER(2500016) are still exported but deprecated, since Codama v2 removesresolverValueNodeand they are no longer thrown.
Minor Changes
-
#1258
1f0fb88Thanks @lorisleiva! - Reject v1 instructions whose upgrade would provide clashing values under the same key, instead of producing conflictingprovidesentries. Providing a contextual argument default under a key already provided with a different value, or under the key of a v1 injection it would then resolve, now throws the newCODAMA_ERROR__CANNOT_UPGRADE_CONFLICTING_PROVIDED_KEYerror, while identical values are provided once. -
#1256
e92df74Thanks @lorisleiva! - Fix gaps in dynamic account address resolution and type generation. Required accounts whose default value resolves to nothing, e.g. an omitted optional account, now throwCODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSINGinstead of being left out of the instruction, PDA seeds injected from anaccountValueNoderesolve to the address of that account, and reading account data withoutfetchAccountsthrows the newCODAMA_ERROR__DYNAMIC_CLIENT__FETCH_ACCOUNTS_MISSING(2500022) error instead of aTypeError. Generated types follow the program of defined type links, and reference recursive defined types through${Type}Argsaliases emitted by the newgenerateDefinedTypesfunction instead of overflowing the stack.BREAKING CHANGES
Path-based codegen helpers.
codamaTypeToTSandgetResolutionRefsfrom@codama/dynamic-address-resolution/codegentake the path of their type or instruction, and optional linkables, instead of the defined types of the main program, so that links resolve within the right program.- codamaTypeToTS(instruction.data, root.program.definedTypes); - getResolutionRefs(instruction, root.program.definedTypes); + codamaTypeToTS([root, root.program, instruction, instruction.data]); + getResolutionRefs([root, root.program, instruction]);
-
#1261
bb09077Thanks @lorisleiva! - Render every node path of an error context as node selectors in error messages, not onlypath, as well as lists of node paths, e.g. acycle.getNodePathStringfalls back to thenameof nodes that have noidentifier, so v1 nodes render too. -
#1221
b869cefThanks @tsiklic1! - AddaddProgramsVisitorto append programs to a root node's additional programs, rejecting identifiers that collide with existing or other new programs after conversion to camelCase.