Profiles

Profile diagnostics

Every E_, W_ and I_ code the resolver, the consent generator and the formatters return.

The resolver and the validator report problems as a list of diagnostics; the formatters, the consent generator and the terms functions throw an error that carries a code. Either way, match on the code: the message is written for a person or a model to read. Codes are grouped below by the package that returns them, with the spec's §13 table first. Every code here is copied from spec §13 or from the package's source under profile/packages.

tsprofile/packages/resolver/src/browser.d.mts
export interface Diagnostic {
  severity: "error" | "warning" | "info";
  code: string;
  /** A JSON pointer for E_SCHEMA, an address (`send(0).to`, `type:Tokens.e8s`) or a document path (`binds.interface_id`). */
  at: string;
  message: string;
  /** The profile's name, when the diagnostic comes from one. */
  profile?: string;
}
WhereHow a failure arrivesCodes
@meantjs/profile (resolveService, validateProfile, the candid-profile CLI)diagnostics: Diagnostic[]; ok is false when one is an error§13, doc annotations
@meantjs/profile/evmthrows AbiError with codeAbiError
@meantjs/formatthrows FormatError with code; safeParse and safeDisplay return itFormatError
@meantjs/consent and its subpathsthrows ConsentError; icrc21ConsentMessage maps it to an ICRC-21 error; adjustments go to diagnosticsConsentError, diagnostics
@meantjs/consent/termsthrows TermsError with code for a term the agent wrote that cannot be read, or a step out of order; ConsentError EE_REQUEST for input not in the shape the functions writeTermsError
@meantjs/toolsreadToolInput returns { issues }input issues
@meantjs/reconcileno codes: matchBlocks returns a statusstatuses

The candid-profile CLI exits with 0 when no diagnostic is an error, 1 when one is (the resolved form is still printed when the service compiles), and 2 for a usage or I/O problem (The candid-profile command).

Resolver and validator: spec §13#

Returned by @meantjs/profile. Rows that §13 groups (E_ADDR_SYNTAX / E_ADDR_UNRESOLVED) are split here, one code a row, with the meaning that half of the §13 row gives.

Schema, interface and input#

CodeSeverityMeaning
EE_SCHEMAerrorFails the JSON Schema. at is a JSON pointer.
EE_CANDIDerrorThe interface (requires or --did) does not compile.
EE_ENVELOPEerrorThe interface was given as a candid-core ContractEnvelope (--envelope) that the resolver cannot read: not an object, no contract, a contract.format other than candid-core, a format_version other than 1, no contract.identities.interface, a type reference outside contract.types, or any other failure of candid-core's own structural or canonical checks. No resolved form is produced.
EE_SERVEDerrorA profile a canister serves (§8.1) that cannot be used: its bytes are not UTF-8 JSON (or start with a byte order mark), it is over 1 MiB, it is not one JSON object of kind: "canister" and origin: "author", or its binds.canister_id names another canister. The profile is not applied; the rest of the service resolves without it.
EE_ABIerrorAn EVM ABI (binds.abi, or the contract's given as the interface) that cannot be read: a fragment that does not parse, a type that does not exist, an overloaded function name (O1), two components with one field id, or no function at all (§15.1).
EE_CHAINerrorA profile or pack for an EVM contract given for a Candid service, or the other way round (§15.3).
EE_ADDRESS_CHECKSUMerrorA deployment address in mixed case that does not match its EIP-55 checksum (§15.3).
EE_EIP712errorbinds.eip712.types that cannot be read (a struct name that is not an identifier or reads as an ABI type or EIP712Domain, a member type that is not canonical or not a type, a struct that contains itself or refers to a refused one), a message that shares its name with a function, two profiles that give one type name different members, or types with no message and no function (§15.9). Experimental.
WW_NO_INTERFACEwarningCanister profile checked without its .did; semantic checks skipped.

Addresses and tags#

CodeSeverityMeaning
EE_ADDR_SYNTAXerrorAddress does not parse.
EE_ADDR_UNRESOLVEDerrorAddress does not resolve.
EE_PACK_TYPE_REFerrortype: address in a pack.
EE_TYPE_NODEerrorPathless type: address on a declaration that is not a record or a variant.
EE_TAG_TARGETerrorWrong kind of target. Includes an intent or effect at a value address that is not a case of a variant in the arguments, or that steps into [] (§5.2), and on an EVM contract idempotency, outcome, list, names and named (not yet) (§15.4).
EE_TAG_NOT_APPLICABLEerrorWrong Candid type. Includes account and subaccount on an EVM contract (no ABI type) (§15.4).
EE_REF_UNRESOLVEDerrorBad dynamic value: the query: method is not in the interface.
EE_REF_NOT_QUERYerrorBad dynamic value: the query: method is not a query.
EE_REF_SHAPEerrorBad dynamic value: the method takes arguments, or does not return exactly one value.
EE_REF_TYPEerrorBad dynamic value: the method returns the wrong kind (a number expected, or text).
EE_DYNAMIC_KINDerrorBad dynamic value: now or caller where only query: is valid.
EE_DEFAULT_NULLerrornull default on a non-optional position.
EE_TOKEN_PATHerrorAn amount.token that is not a relative path to an address in the same argument and the same array element as the amount, or that is given on a Candid service (§15.9, OQ-6). Experimental.
WW_STRUCTURAL_ALIASwarningA type: address starts from a declaration whose type another declaration also names; the tag reaches both (§3.2 rule 7).
II_UNTAGGED_NUMERICinfoA numeric update argument has no meaning attached.

Methods: effect, idempotency, outcome, templates#

CodeSeverityMeaning
EE_EFFECT_MODEerrorAn effect that does not fit the method: a query or composite query declared as something other than read, or replicated: true anywhere but on an update method with kind: "read" and irreversible: false (§5.3).
WW_EFFECT_MODEwarningA read on an update or a oneway method, except the read-only update form (§5.3).
EE_CASE_OVERLAPerrorTwo tagged cases of one method, for the same tag, that one value can take both (§5.2).
EE_CASE_EFFECTerrorA case effect that needs confirmation, or is irreversible, under a method effect that does not or is not (§5.3).
EE_GRANTerrorA grant on an effect that is not a method's transfer or approve (another kind, a case effect), an approve's grant with to, or a position that breaks §5.3: a path that does not resolve, steps into [] or passes through a case of a variant; a spender or to that is neither an address nor account-tagged; an amount that is neither an unsigned amount-tagged position nor a bool; an optional spender, to or amount; an ends position without a timestamp tag (§5.3, D-056). In a pack applied to a service, the grant is dropped instead (II_PACK_ANNOTATION_SKIPPED, below).
EE_IDEMPOTENCY_MODEerrorIdempotency on a query.
EE_STAMP_UNTAGGEDerrorStamp without a timestamp tag.
WW_STAMP_REQUIREDwarningThe stamp field is not optional; the tool layer must always fill it.
EE_OUTCOME_NOT_CASEerrorOutcome key is not a variant case.
WW_OUTCOME_UNCLASSIFIEDwarning, or info when default is setA result case without a class.
EE_TEMPLATEerrorTemplate syntax, or a [ ] segment on an EVM contract (§15.4).
EE_TEMPLATE_PATHerrorUnknown placeholder, or one through another case of a variant on a case intent's path (§6).
WW_TEMPLATE_OPTIONALwarningA placeholder that resolves to an opt position outside [ … ] (§6).

Names#

CodeSeverityMeaning
EE_NAMES_MODEerrorA names set on a method that is not a query or a read-only update.
EE_NAMES_SHAPEerrorA names set on a method that takes arguments, or whose items is not a vec of records.
EE_NAMES_FIELDerrorA names set whose name is not text.
EE_NAMES_SET_DUPLICATEerrorA names set declared twice.
EE_NAMED_SETerrorA named position whose set is not declared (or has no show for by: "show").
EE_NAMED_TYPEerrorA named position whose type differs from the set's field.
WW_NAMED_UNPATTERNEDwarningA named text position without a text.pattern: names are looked up before values.

Layers, binding and packs#

CodeSeverityMeaning
EE_CONFLICTerrorTwo different values for one tag at one position (within one layer, at one specificity; the first one given is kept).
WW_DUPLICATEwarningEqual values for one tag at one position and specificity (§8); a deployment listed twice (§15.3).
WW_OVERRIDDENwarningThe same tag at the same position in a lower layer, dropped (§8).
WW_REBOUNDwarningInterface changed; reported first, then either confirmed or followed by EE_STALE.
EE_STALEerrorBound interface changed and some address or tag no longer holds.
EE_PACK_NOT_MATCHEDerrorA pack the caller asked for explicitly does not apply to the service.
WW_PACK_NO_DEFAULTwarningA pack outcome tag without a default (§7).
II_PACK_MATCHEDinfoA pack applies; the message lists every result variant wider than the fragment (D-019) and its extra cases.
II_PACK_NOT_MATCHEDinfoA candidate pack from the pack search does not apply; the message gives the first reasons.
II_PACK_ANNOTATION_SKIPPEDinfoA matched pack names a position the service lacks, which subtyping allows; the annotation is dropped. Since 0.4.0 also a pack's grant that does not hold in the service it is applied to: the grant is dropped and the effect kept ("effect grant dropped, the effect kept: E_GRANT: …"; §5.3).

A stale canister profile loses its value-conversion tags in the resolved form and keeps the rest; see Profiles, layers and binding. The codes that make a profile stale when they appear after a rebind are listed in STALE_CODES in checks.mjs.

Resolver: doc annotations#

Returned by profileFromDocAttributes when it turns the tags written as doc comments in a .did into an author profile (spec §9, Annotate a .did file). Not in §13. On an error the profile is still returned with what could be placed. Meanings are those of the package's README and src/doc-annotations.mjs.

CodeSeverityMeaning
EE_DOC_INPUTerrorNot a doc attributes v1 response.
EE_DOC_SYNTAXerrorcandid-core refused the comment. candid-core's compile failures pass through as EE_CANDID.
EE_DOC_TARGETerrorA tag no v0 address reaches, such as inside a func value or a callback service, or one in the wrong place.
EE_DOC_VALUEerrorA value that cannot be read: a fraction, an unknown call.
WW_DOC_UNKNOWN_TAGwarningA bare name one or two letters from a tag (@amout): not a profile tag.
II_DOC_IGNOREDinfoThe doc comments hold no profile tag, so there is no profile; or a name that is not a profile tag (a dotted name such as @ui.hidden belongs to another tool).
II_DOC_PROSEinfoProse not attached as describe.help: on an integer the same doc gives no value tag, prose would make it an agent input without a unit (D-044).

@meantjs/profile/evm: AbiError#

The EVM helpers throw AbiError (name: "AbiError", code). Experimental, spec §15; see EVM contracts.

CodeSeverityMeaning
EE_ABIerror, thrownA fragment that cannot be read (parseSignature). parseAbi lists its problems instead of throwing.
EE_ABI_ENCODEerror, thrownA value encodeParams, encodeCall or typedDataDigest cannot encode: an integer that is not a decimal string or a bigint, or outside its type; the wrong number of array elements; a missing or unknown tuple component; text that is not well formed.
EE_ABI_DECODEerror, throwndecodeParams: the data is not the canonical ABI encoding of its values (dirty padding, a non-canonical offset or trailing bytes), ends early, or is over the limits.
EE_ADDRESSerror, thrownNot an address (0x and 40 hex digits).
EE_ADDRESS_CHECKSUMerror, thrownreadAddress: an address in mixed case that does not match its EIP-55 checksum.
EE_EIP712error, thrownencodeType and eip712TypeHash: a primary type that is not in the types (§15.9). parseEip712Types lists its problems instead of throwing; the resolver reports them as the EE_EIP712 diagnostic above.

@meantjs/format: FormatError#

Every rejection of the format library is a FormatError with a stable code, one of CODES. The meanings are the comments in src/errors.mjs where it has one, and otherwise the messages the code is thrown with. See Parse and display values.

CodeGroupMeaning
EE_TYPEsharedWrong JavaScript type for an input, for example a number where a decimal string is required.
EE_SYNTAXsharedThe text does not match the grammar.
EE_RANGEsharedOutside the range of the Candid type or of the representable calendar.
EE_TOO_LONGsharedInput longer than the bound on work.
EE_ARGsharedA tag argument is missing or invalid.
EE_TAG_TYPEsharedThe tag does not apply to this Candid type.
EE_TAG_CONFLICTsharedTwo formatting tags at one position.
EE_REF_UNRESOLVEDsharedA dynamic value was not supplied by the caller.
EE_EXCESS_PRECISIONamountMore fractional digits than decimals (never rounded).
EE_NEGATIVEamountNegative input for an unsigned Candid type.
EE_SYMBOL_MISMATCHamountThe symbol in the input is not the token's symbol.
EE_INEXACTtimeThe value cannot be represented exactly in the requested unit.
EE_CALENDAR_UNITtimeYears and months have no fixed length.
EE_NEEDS_NOWtimeRelative time without a now.
EE_CHECKSUMaccount, subaccount, bytesChecksum does not match.
EE_CHECKSUM_MISSINGaccount, subaccount, bytesAn account text with a subaccount but no checksum (the form is <principal>-<checksum>.<subaccount>).
EE_NOT_CANONICALaccount, subaccount, bytesA valid value written in a non-canonical way.
EE_PRINCIPALaccount, subaccount, bytesInvalid principal text.
EE_HEXaccount, subaccount, bytesText that is not hexadecimal.
EE_BASE64account, subaccount, bytesNot base64: outside the standard alphabet, an impossible length, wrong = padding, or unused trailing bits that are not zero.
EE_UTF8account, subaccount, bytesText that cannot be encoded as UTF-8 (lone surrogate).
EE_LENGTHaccount, subaccount, bytesWrong length in bytes.
EE_MAX_LENaccount, subaccount, bytesLonger than the tag's max_len.

formatterFor throws EE_REF_UNRESOLVED, EE_ARG, EE_TAG_TYPE or EE_TAG_CONFLICT rather than return a formatter that half works. Since 0.3.0 that includes an amount whose token names its token by a field when the caller passes no token (EE_REF_UNRESOLVED), and a timestamp threshold without its message, or the other way round (EE_ARG: "a timestamp threshold and its message go together: give both or neither"). The Rust crate meant-format returns eight of these codes for the amount tag, matched case by case against this package: meant-format (Rust).

Every failure of the consent package is a ConsentError with a stable code. icrc21ConsentMessage maps it to an ICRC-21 error variant whose description starts with the code; the lower-level functions throw it. Meanings are the comments in src/errors.mjs. See Generate consent messages.

CodeICRC-21 errorMeaning
EE_METHOD_UNKNOWNUnsupportedCanisterCallThe resolved form has no such method.
EE_DECODEUnsupportedCanisterCallThe argument bytes do not decode against the method's signature (for an EVM call: calldata that is not the canonical encoding of its values; for an EIP-712 request: values that are not exactly the message's members, canonically written).
EE_TOO_LARGEUnsupportedCanisterCallThe arguments exceed the bounds of a consent message (never truncated).
EE_LANGUAGEUnsupportedCanisterCallOnly with languagePolicy: "error": the requested language is not supported.
EE_REQUESTUnsupportedCanisterCallThe ICRC-21 request itself is malformed. From @meantjs/consent/evm: malformed input (the calldata, to, chainId, form or tokens, or a typedData whose shape or types cannot be read). From generateConsent: a canisterId that is not a principal's text. From @meantjs/consent/terms: a wallet, terms or grant not in the shape the functions write, terms changed after confirmTerms, or a termsGate check without a request id (below).
EE_DEPLOYMENT(EVM only)An EVM call's target is not a deployment its profile lists (spec §15). From eip712Consent: the request's verifying contract on its chain is not one the profiles list. From erc7730Descriptor: no deployment to bind the file to.
EE_DOMAIN(EVM only)An EIP-712 request's domain is for another chain, contract or name than its profile's (spec §15.9). eip712Consent also refuses a domain with a field EIP-712 does not define, a salt, no chainId, no verifyingContract, or a types.EIP712Domain that does not list the domain's fields in EIP-712 order. Experimental.
EE_TYPE_HASH(EVM only)No message of the resolved form has the request's EIP-712 type hash (spec §15.9): a request is matched by its type hash, never by its name. Experimental.
EE_UNSUPPORTED_TYPEConsentMessageUnavailableA position the resolved form cannot type (recursive cut, func, service). On an EVM contract also a payable function, whose native value has no position yet.
EE_RESOLVED_FORMGenericError 1000The resolved form is malformed. Also an EVM resolved form given to the main entry, and a Candid one given to @meantjs/consent/evm; for eip712Consent, a message whose encode_type does not hash to its type_hash.
EE_TEMPLATEGenericError 1001The intent template does not parse.
EE_TEMPLATE_PATHGenericError 1002A placeholder names a position the method does not have.
EE_REF_UNRESOLVEDGenericError 1100Pass-through of the format library: a dynamic ref the caller did not supply. On EVM also an amount in a token that is not in tokens.
EE_ARGGenericError 1101Pass-through of the format library: a bad tag argument.
EE_TAG_TYPEGenericError 1102Pass-through of the format library: the tag does not apply to the type.
EE_TAG_CONFLICTGenericError 1103Pass-through of the format library: two formatting tags at one position.
EE_EXPORT(EVM only)The ERC-7730 export: the resolved form says something an ERC-7730 file cannot say (spec §15). What a file cannot say but that changes no value (a timestamp's words, a template over an array) is not refused: it is left out and listed in the export's notes.
EE_INTERNALGenericError 1999Not a ConsentError: any other thrown value, reported with this code in diagnostics.

A formatter that cannot be built stops the message (rule 10 of spec §12): a number is never shown without its decimals.

What the generator adjusted, in the non-enumerable diagnostics of a result ({ code, at, message }, no severity field). The message is still produced.

CodeSeverityMeaning
WW_TEMPLATE_FALLBACKwarningA template that fails at consent time; the generic intent is used instead (spec §12 rule 12).
WW_FORMAT_FALLBACKwarningA formatter refused the value; it is shown as raw Candid text (spec §12 rule 10).
WW_GRANTwarningA grant that cannot be read from the request (generateConsent with a canisterId, evmConsent, eip712Consent): grant is null, at is the method or message, and the message says why, then "the request has no grant, so terms the user confirmed cannot cover it". The text is the same either way (§5.3, D-056).
WW_UTC_OFFSET_IGNOREDwarningutc_offset_minutes outside ±24 h; UTC is used (spec §12 rule 6).
II_LANGUAGE_FALLBACKinfoThe requested language is not supported; the message is in "en" and the metadata says so (spec §12 rule 9).

New in 0.4.0 (spec §5.3, "Confirmed terms", D-056). readTerms and termsGate throw TermsError (name: "TermsError", code, one of TERMS_CODES). Its message is written for the agent, which fixes the term or asks the person; readTerms never guesses a token, an app, a number of decimals or a date. Meanings are the comments in src/terms.d.mts, and the messages are those of src/terms.mjs, with the parts in angle brackets filled in and some shortened to their last clause. See Confirm terms for a task.

CodeMeaning and messages
EE_TERMS_MISSINGTERMS_CODES.MISSING. A field is missing or empty, or both spender and to are given. missing parameter: <field> (for the party, missing parameter: spender or to); give spender or to, not both: spender for who may spend the tokens, to for who is paid directly.
EE_TERMS_TOKENTERMS_CODES.TOKEN. A token the wallet does not know. the wallet knows no token named "<token>"; it knows <symbols>. If the user named another token, or did not say which, ask the user.
EE_TERMS_PARTYTERMS_CODES.PARTY. An app the wallet does not know, or an address or account that is not one. the wallet knows no app named "<name>"; it knows <apps>. If the user named another app, or none, ask the user which app they mean, or for its address (account for an ICP token; only the apps on the token's chain are listed); <role> "<text>" is not a 0x address with 40 hex digits; an address in mixed case whose EIP-55 checksum does not match (a character may be mistyped. Ask the user to check the address); <role> must be <what>; got "<text>" when the wallet knows no app on that chain; and an app the wallet knows only on the other chain.
EE_TERMS_AMOUNTTERMS_CODES.AMOUNT. An amount that cannot be read, or has more decimals than its token: never rounded. max_amount: and the parseAmount message, such as max_amount: "1.0000000000000000001" has 19 fractional digits but this token has 18; amounts are never rounded, so give at most 18.
EE_TERMS_ENDTERMS_CODES.END. An end that cannot be read, or a date before today. expires_by must be a date as YYYY-MM-DD, a length of time from now as a number and a unit (hours, days, weeks, months or years), such as "2 hours", "30 days" or "1 month", or "never"; got "<text>"; expires_by <date> is before today, <today>; an end after the year 9999 (write "never" only if the user plainly accepts no end).
EE_TERMS_ORDERTERMS_CODES.ORDER. termsGate: a step out of order. read() before the person confirmed (there are no terms yet: propose the user's terms, and read the request once the user confirms them, or the user has not confirmed the terms yet; the request can be read once they do); confirm(shown) with no draft, or with text that is not the draft's (show termsText(gate.proposed) and ask again); check before read() (read the request first: its grant is checked against the terms it was read under); a second request (these terms cover one request, the one already checked; another request is a new task, with new terms); and propose, confirm or reject once the request was read (the request was read under the confirmed terms, so they cannot be changed now; new terms start a new task).

Input that is not in the shape these functions write is a ConsentError EE_REQUEST, not a TermsError: a wallet without its tokens or with a now that is not a bigint, terms that did not come from readTerms or changed after confirmTerms (terms are not the ones the user confirmed: they changed after confirmTerms …), a grant that did not come from the consent functions, and a termsGate check with no request id. checkGrant throws neither for a grant that does not fit: it returns { fits: false, reasons }, the reasons in words.

@meantjs/tools: input issues#

readToolInput returns { issues: [{ param, path, code, message }] } instead of a value when the inputs cannot be read. The codes are the format library's, above, plus these (from the function's documentation in src/input.mjs). Inside a JSON input, path names the place ($args[0].command.Follow.followees[1].id). See Give an agent tools.

CodeSeverityMeaning
EE_INPUTerrorThe inputs are not an object.
EE_UNKNOWN_PARAMerrorAn input the tool does not have, or a key a JSON input does not have.
EE_MISSINGerrorA required input is missing.
EE_TYPEerrorAn input that is not text, or JSON of the wrong shape for a record, variant or vec input.
EE_NAMES_UNREADerrorA named input whose set's names were not read.
EE_NAME_NOT_FOUNDerrorThe text is not a value at the position, and no entry of the set has that name.
EE_NAME_AMBIGUOUSerrorSeveral entries have the name: ask the person which.
EE_ARGerrorA tag argument the layer cannot use, such as a text.pattern it does not run.

An EVM contract's resolved form ("chain": "evm") is refused by the tool layer with a TypeError, not a code: EVM tools are a later phase.

@meantjs/reconcile: statuses#

@meantjs/reconcile returns no diagnostic codes. matchBlocks judges the ICRC-3 blocks read since the first send and returns one of four statuses (Settle an unknown outcome):

StatusFieldsMeaning
foundblockA block carries exactly this transaction.
absentclosedBy: answered, too_old or window_passed; clock?Nothing can still land: every send was answered, a send was answered TooOld, or the ledger's clock is past the stamp's window.
not_yetopenUntil?, reason?, clock?No match, but a send may still land.
unreadablereason, lookalike?The range was not fully read, a block in it cannot be read, or a lookalike block carries the call's stamp and amount in another shape. Never absent.