Skip to content

Tokenization precompile errors: the nine codes from errors.go, the uint64 range trap, common failures with fixes, Solidity handling, debugging.

Every tokenization precompile failure reverts with a PrecompileError in the form precompile error [code=N]: message: details. This page lists the codes, the common failures, and how to handle them in Solidity.

solidity
try precompile.transferTokens(json) returns (bool success) {
    require(success, "Transfer failed");
} catch Error(string memory reason) {
    // reason = "precompile error [code=4]: transfer failed: ..."
    revert(reason);
}

Error Codes

From x/tokenization/precompile/errors.go.

CodeNameMessageRaised when
1InvalidInputinvalid input parametersBad JSON, missing or mistyped field, failed ValidateBasic, zero address, invalid range, amount zero, size limit exceeded
2CollectionNotFoundcollection not foundThe collection ID does not exist (ErrCollectionNotExists, ErrInvalidCollectionID)
3BalanceNotFoundbalance not foundThe user balance store does not exist (ErrUserBalanceNotExists)
4TransferFailedtransfer failedDisallowed transfer, underflow (insufficient balance), overflow (ErrDisallowedTransfer, ErrUnderflow, ErrOverflow)
5ApprovalFailedapproval operation failedAn approval message failed in the keeper
6QueryFailedquery failedAccount, address list, or approval not found; other keeper query errors (ErrAccountNotFound, ErrAddressListNotFound, ErrApprovalNotFound, ErrNotFound)
7InternalErrorinternal errorNil response, marshal failure, value above uint256
8Unauthorizedunauthorized operationZero-address caller, inadequate approvals, manager or permission checks (ErrInadequateApprovals, ErrUnauthorized)
9CollectionArchivedcollection is archived (read-only)Write to an archived collection (ErrCollectionIsArchived)

Keeper errors are mapped by MapCosmosErrorToPrecompileError; unmapped errors take the default code of the handler that caught them. Details are sanitized and truncated to 500 characters. Field-level input errors carry a path such as field 'transfers[0].balances[0].amount': ....

The uint64 Trap

The most common error for new developers. IDs and timestamps are uint64 on the chain.

solidity
// Wrong: causes a range overflow error
string memory ownershipJson = TokenizationJSONHelpers.uintRangeToJson(1, type(uint256).max);

// Correct: use the FOREVER constant
string memory ownershipJson = TokenizationJSONHelpers.uintRangeToJson(
    1,
    TokenizationJSONHelpers.FOREVER  // = type(uint64).max = 18446744073709551615
);
ConstantValueUse
FOREVER18446744073709551615Ownership times that never expire
MAX_TIME18446744073709551615Maximum valid timestamp
MAX_ID18446744073709551615Maximum valid token ID
MIN_ID1Minimum valid ID (ranges start at 1)
FOREVER_STR"18446744073709551615"For direct JSON string use

Defined in both TokenizationJSONHelpers and TokenizationHelpers.

Handling Errors in Solidity

Basic:

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./interfaces/ITokenizationPrecompile.sol";
import "./libraries/TokenizationJSONHelpers.sol";

contract SafeTransfer {
    ITokenizationPrecompile constant precompile =
        ITokenizationPrecompile(0x0000000000000000000000000000000000001001);

    function safeTransfer(string memory json) external {
        try precompile.transferTokens(json) returns (bool success) {
            require(success, "Transfer failed");
        } catch Error(string memory reason) {
            // Precompile error with message
            revert(reason);
        } catch (bytes memory lowLevelData) {
            // Low-level error - decode if possible
            revert("Unknown precompile error");
        }
    }
}

With the TokenizationErrors library, which validates before the call:

solidity
import "./libraries/TokenizationErrors.sol";

contract MyContract {
    using TokenizationErrors for *;

    function transfer(uint256 collectionId, string memory json) external {
        // Validate inputs before calling precompile
        TokenizationErrors.requireValidCollectionId(collectionId);
        TokenizationErrors.requireNonEmptyString(json, "JSON");

        bool success = precompile.transferTokens(json);
        require(success, "Transfer failed");
    }
}

Common Failures

Range Value Overflow

text
precompile error [code=1]: invalid input parameters: message validation failed: invalid balance times:
range at index 0 has end 115792089237316195423570985008687907853269984665640564039457584007913129639935
greater than max 18446744073709551615

Cause: type(uint256).max instead of type(uint64).max.

solidity
// Use the FOREVER constant
string memory ownershipJson = TokenizationJSONHelpers.uintRangeToJson(
    1,
    TokenizationJSONHelpers.FOREVER
);

// Or use the MAX_TIME/MAX_ID constants from TokenizationHelpers
uint64 maxTime = TokenizationHelpers.MAX_TIME;

Address Cannot Be Empty

text
precompile error [code=1]: invalid input parameters: address cannot be empty

Cause: a wrong field name, or an empty address. Query requests accept userAddress as an alias of address only for getBalance and getDynamicStoreValue; messages do not.

solidity
// Wrong: "userAddress" is not a field of MsgSetDynamicStoreValue
'{"storeId":"1","userAddress":"0x0bc63cfe31d5218eb414b142c799e20964a54a1a","value":true}'

// Correct: use "address"
'{"storeId":"1","address":"0x0bc63cfe31d5218eb414b142c799e20964a54a1a","value":true}'

// Or use the helper
string memory json = TokenizationJSONHelpers.setDynamicStoreValueJSON(
    storeId,
    userAddress,  // address type, not string
    true
);

Failed to Unmarshal JSON

text
failed to unmarshal JSON for method X: precompile error [code=1]: invalid input parameters: ...

Causes: invalid JSON syntax (missing quotes, commas, brackets); wrong field types (numbers as raw numbers, booleans as strings); missing required fields; unknown fields.

TypeCorrectWrong
Numbers"123"123
Booleanstrue / false"true" / "false"
Addresses"0x0bc63cfe31d5218eb414b142c799e20964a54a1a"0x0bc63cfe31d5218eb414b142c799e20964a54a1a (unquoted)
Ranges[{"start":"1","end":"100"}][{start:1,end:100}]
json
{
  "storeId": "123",
  "address": "0x0bc63cfe31d5218eb414b142c799e20964a54a1a",
  "value": true
}

Collection Not Found

text
precompile error [code=2]: collection not found: collectionId: 12345
solidity
// Check collection exists before operations
try precompile.getCollection(TokenizationJSONHelpers.getCollectionJSON(collectionId)) {
    // Collection exists, proceed
} catch {
    revert("Collection does not exist");
}

Insufficient Balance

text
precompile error [code=4]: transfer failed: underflow error: ...

Cause: the transfer exceeds what the sender holds for those token IDs and ownership times.

solidity
// Check balance before transfer
uint256 balance = precompile.getBalanceAmount(
    TokenizationJSONHelpers.getBalanceAmountJSON(
        collectionId,
        msg.sender,
        tokenId,
        block.timestamp
    )
);
require(balance >= amount, "Insufficient balance");

Inside a contract, msg.sender here is the contract's own caller, but the precompile transfers from the contract's balance. Check the address that actually holds the tokens.

Not Authorized

text
precompile error [code=8]: unauthorized operation: ...

Causes: the caller is not the collection manager; no approval covers the transfer; the permission is locked in the collection permissions; the time window for the operation has passed.

Debugging steps:

  1. Check who the collection manager is (getCollection).
  2. Verify the outgoing, incoming, and collection approvals cover the transfer.
  3. Check whether the permission is locked (permanentlyForbiddenTimes).
  4. Verify the current time is inside the allowed window.
solidity
// Get collection to check manager
bytes memory collectionBytes = precompile.getCollection(
    TokenizationJSONHelpers.getCollectionJSON(collectionId)
);
// Decode off-chain and check the manager field

// For transfers, ensure approvals are set
// Check outgoing approval from sender
// Check incoming approval for recipient

Concepts: Transferability, Permissions.

Collection Archived

text
precompile error [code=9]: collection is archived (read-only): collectionId: 123
solidity
// If you are the manager and need to modify, unarchive first
string memory json = TokenizationJSONHelpers.setIsArchivedJSON(
    collectionId,
    false,  // unarchive
    "[]"    // canArchiveCollection permission
);
precompile.setIsArchived(json);

Invalid Range (Start > End)

text
precompile error [code=1]: invalid input parameters: invalid range: start 100 is greater than end 50
solidity
// Validate ranges before building JSON
require(startTime <= endTime, "Invalid time range");
require(startTokenId <= endTokenId, "Invalid token ID range");

string memory rangeJson = TokenizationJSONHelpers.uintRangeToJson(startTime, endTime);

EVM Query Challenge Failed

A transfer gated by an EVM query challenge or an invariant fails as a transfer or authorization error (code 4 or 8) with the challenge result in the details, for example contract returned 0, expected >= 1.

Debugging:

  1. Check which contract the challenge calls.
  2. Verify the calldata (including $sender style placeholders).
  3. Check the expected result and the comparison operator.
  4. Confirm the target contract is deployed and returns a value.
solidity
// Test the EVM query manually before using in invariants
(bool success, bytes memory result) = targetContract.staticcall(callData);
require(success, "EVM call failed");
uint256 value = abi.decode(result, (uint256));
require(value >= 1, "challenge would fail: contract returned 0, expected >= 1");

Dynamic Store Not Found

text
precompile error [code=6]: query failed: ... store 999 does not exist
solidity
// Verify store exists
try precompile.getDynamicStore(TokenizationJSONHelpers.getDynamicStoreJSON(storeId)) {
    // Store exists
} catch {
    // Create the store first
    uint256 newStoreId = precompile.createDynamicStore(
        TokenizationJSONHelpers.createDynamicStoreJSON(false, "", "")
    );
}

Approval Not Found

text
precompile error [code=6]: query failed: approval "my-approval" does not exist

Cause: deleting or referencing an approval ID that does not exist.

solidity
// Approvals are identified by approvalId string. Delete inside try/catch so a
// missing approval does not revert the whole call.
try precompile.deleteOutgoingApproval(
    TokenizationJSONHelpers.deleteOutgoingApprovalJSON(collectionId, "my-approval")
) returns (bool) {
    // deleted
} catch Error(string memory reason) {
    // "precompile error [code=6]: query failed: approval \"my-approval\" does not exist"
    emit ApprovalMissing(reason);
}

Invalid Approval Criteria

text
precompile error [code=1]: invalid input parameters: message validation failed: merkle root is required for merkle challenge

Common causes: a merkle challenge without a root; voting criteria without a proposal ID; an approval tracker without limits. Field reference: Approval Criteria.

Debugging

Log the JSON before sending:

solidity
// Emit event with JSON for debugging (remove in production)
event DebugJSON(string json);

function debugTransfer(uint256 collectionId, address to, uint256 amount) external {
    address[] memory recipients = new address[](1);
    recipients[0] = to;
    string memory json = TokenizationJSONHelpers.transferTokensJSON(
        collectionId,
        recipients,
        amount,
        TokenizationJSONHelpers.uintRangeToJson(1, 1),
        TokenizationJSONHelpers.uintRangeToJson(1, TokenizationJSONHelpers.FOREVER)
    );
    emit DebugJSON(json);
    precompile.transferTokens(json);
}

Validate the JSON outside the chain: copy it from the log, check it in a JSON validator, and compare field names against the message page.

Test components on their own:

solidity
// Test range construction
string memory rangeJson = TokenizationJSONHelpers.uintRangeToJson(1, 100);
// Expected: [{"start":"1","end":"100"}]

// Test address conversion
string memory addrStr = TokenizationJSONHelpers.addressToString(0x0bc63cfe31d5218eb414b142c799e20964a54a1a);
// Expected: 0x0bc63cfe31d5218eb414b142c799e20964a54a1a

Check that the precompile responds:

solidity
// Simple connectivity test
try precompile.params("{}") {
    // Precompile is responding
} catch {
    revert("Precompile not available");
}

Convert the caller for a Cosmos-side check:

solidity
// Convert EVM address to bech32 for checking on Cosmos side
string memory bech32 = precompile.convertEvmAddressToBech32(0x0bc63cfe31d5218eb414b142c799e20964a54a1a);
// Returns: bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d

JSON Quick Reference

Field typeJSON formatExample
uint256String"123456789"
uint64String"18446744073709551615"
boolRaw booleantrue or false
addressHex string or bech32"0x0bc63cfe31d5218eb414b142c799e20964a54a1a" or "bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d"
stringQuoted string"hello world"
UintRange[]Object array[{"start":"1","end":"100"}]
string[]String array["a","b","c"]
Empty object{}{}
Empty array[][]

Edit this page on GitHub