Loading...
Loading...
Diagnoses and fixes Aptos Move compilation, runtime, and deployment errors. Triggers on: 'error', 'fix this', 'debug', 'troubleshoot', 'why is this failing', error codes like 'EOBJECT_DOES_NOT_EXIST', 'ABORTED', 'RESOURCE_NOT_FOUND', 'Type mismatch', 'ability constraint'.
npx skill4agent add iskysun96/aptos-agent-skills troubleshoot-errorsacquiresobject::address_to_object<T>()acquires ResourceType[addresses]object::transfer_with_ref()object::transfer()references/error-catalog.md// ❌ WRONG: Storing collection's extend_ref
fun init_module(deployer: &signer) {
let collection_ref = collection::create_unlimited_collection(...);
let collection_signer = object::generate_signer(&collection_ref);
move_to(&collection_signer, Config {
extend_ref: object::generate_extend_ref(&collection_ref), // Wrong ref!
});
}
public entry fun mint_nft() acquires Config {
let config = borrow_global<Config>(...);
let signer = object::generate_signer_for_extending(&config.extend_ref);
// ❌ ERROR: Collection can't create tokens in itself
token::create_named_token(&signer, ...);
}// ✅ CORRECT: Create marketplace object that OWNS the collection
fun init_module(deployer: &signer) {
// Create marketplace state object
let marketplace_ref = object::create_named_object(deployer, b"MARKETPLACE_STATE");
let marketplace_signer = object::generate_signer(&marketplace_ref);
// Marketplace creates collection (marketplace is the owner)
collection::create_unlimited_collection(&marketplace_signer, ...);
// Store MARKETPLACE object's extend_ref
move_to(&marketplace_signer, MarketplaceConfig {
extend_ref: object::generate_extend_ref(&marketplace_ref),
});
}
public entry fun mint_nft() acquires MarketplaceConfig {
let config = borrow_global<MarketplaceConfig>(...);
// Use marketplace signer (collection owner)
let marketplace_signer = object::generate_signer_for_extending(&config.extend_ref);
token::create_named_token(&marketplace_signer, ...); // ✅ Works!
}// During deployment, init_module failed an assertion
fun init_module(deployer: &signer) {
assert!(signer::address_of(deployer) == @marketplace_addr, E_NOT_AUTHORIZED);
// If this fails, MarketplaceConfig is never created
move_to(deployer, MarketplaceConfig { ... });
}@marketplace_addraptos move deploy-objectpublish// ❌ WRONG: Incorrect seed or creator address
let obj_addr = object::create_object_address(&wrong_creator, b"SEED");
let config = borrow_global<Config>(obj_addr); // Doesn't exist at this address// ✅ CORRECT: Use correct creator address and seed
let obj_addr = object::create_object_address(&@marketplace_addr, b"MARKETPLACE_STATE");
let config = borrow_global<MarketplaceConfig>(obj_addr);object::transfer()// ❌ WRONG
public entry fun mint_and_transfer(creator: &signer, recipient: address) {
let constructor_ref = token::create_named_token(...);
let transfer_ref = object::generate_transfer_ref(&constructor_ref);
// Disable ungated transfers
object::disable_ungated_transfer(&transfer_ref);
let token_obj = object::object_from_constructor_ref<Token>(&constructor_ref);
// ❌ ERROR: ungated transfers are disabled!
object::transfer(creator, token_obj, recipient);
}// ✅ CORRECT
public entry fun mint_and_transfer(creator: &signer, recipient: address) {
let constructor_ref = token::create_named_token(...);
let transfer_ref = object::generate_transfer_ref(&constructor_ref);
// Disable ungated transfers
object::disable_ungated_transfer(&transfer_ref);
// ✅ Use transfer_with_ref instead
let linear_transfer_ref = object::generate_linear_transfer_ref(&transfer_ref);
object::transfer_with_ref(linear_transfer_ref, recipient);
// Store transfer_ref for future transfers
let token_signer = object::generate_signer(&constructor_ref);
move_to(&token_signer, TokenData { transfer_ref, ... });
}object::disable_ungated_transfer()object::transfer_with_ref()object::transfer()// ❌ WRONG: Inconsistent seeds
let obj = object::create_named_object(creator, b"SEED_V1");
// Later, trying to access with different seed
let obj_addr = object::create_object_address(&creator_addr, b"SEED_V2"); // Wrong seed!// ✅ CORRECT: Use consistent seeds
const SEED: vector<u8> = b"MY_OBJECT_SEED";
// Creation
let obj = object::create_named_object(creator, SEED);
// Access
let obj_addr = object::create_object_address(&creator_addr, SEED);// ❌ WRONG
let item = borrow_global<Item>(item_obj); // Passing Object<Item>, need address
// ✅ CORRECT
let item_addr = object::object_address(&item_obj);
let item = borrow_global<Item>(item_addr);// ❌ WRONG
public fun get_balance(addr: address): u64 { // Missing 'acquires'
let account = borrow_global<Account>(addr);
account.balance
}
// ✅ CORRECT
public fun get_balance(addr: address): u64 acquires Account {
let account = borrow_global<Account>(addr);
account.balance
}// ❌ WRONG
assert!(condition, 0); // Using 0 - unclear what failed
// ✅ CORRECT
const E_CONDITION_FAILED: u64 = 1;
assert!(condition, E_CONDITION_FAILED);use std::debug;
public fun my_function(x: u64, y: u64) {
debug::print(&x);
debug::print(&y);
let result = x + y;
debug::print(&result);
}// When you see: ABORTED: 0x1 (error code 1)
// Find the constant with value 1:
const E_NOT_OWNER: u64 = 1; // This is what failed// Access control: 1-9
const E_NOT_OWNER: u64 = 1;
const E_NOT_ADMIN: u64 = 2;
const E_UNAUTHORIZED: u64 = 3;
// Input validation: 10-19
const E_ZERO_AMOUNT: u64 = 10;
const E_AMOUNT_TOO_HIGH: u64 = 11;
const E_INVALID_ADDRESS: u64 = 12;
// State errors: 20-29
const E_NOT_INITIALIZED: u64 = 20;
const E_ALREADY_INITIALIZED: u64 = 21;
const E_PAUSED: u64 = 22;
// Business logic: 30+
const E_INSUFFICIENT_BALANCE: u64 = 30;~/.aptos/config.yaml.envaptos account listecho $VITE_MODULE_PUBLISHER_ACCOUNT_PRIVATE_KEYenv | grep KEYwrite-contractsgenerate-testssecurity-audit