> ## Documentation Index
> Fetch the complete documentation index at: https://docs.layerzero.network/llms.txt
> Use this file to discover all available pages before exploring further.

# Common Errors

> Common issues and solutions for Common Errors. Troubleshoot problems and find answers to frequently asked questions. LayerZero enables secure crosschain...

This page lists common errors you may encounter when developing LayerZero applications on Sui, along with their causes and solutions.

## Deployment Issues

### Git Dependencies Failed

**Error Message**:

```
Error: Package dependency does not specify published address
Error: Failed to resolve dependencies
```

**Cause**: Git dependencies for LayerZero packages don't work due to missing Move.toml manifests in subdirectories.

**Solution**: Use local dependencies instead:

```bash wrap theme={null}
# Clone LayerZero repo
git clone https://github.com/LayerZero-Labs/LayerZero-v2.git

# Update Move.toml to use local paths
[dependencies]
OApp = { local = "../LayerZero-v2/packages/layerzero-v2/sui/contracts/oapps/oapp" }
EndpointV2 = { local = "../LayerZero-v2/packages/layerzero-v2/sui/contracts/endpoint-v2" }
# ... other packages
```

Or use published package addresses (see [Deployed Contracts](/v2/deployments/chains/sui)).

### Unpublished Dependencies Error

**Error Message**:

```
Error: Modules in package '<package>' were not published with the '--with-unpublished-dependencies' flag
```

**Cause**: Package has dependencies that aren't published onchain.

**Solution**: Add the flag when publishing:

```bash wrap theme={null}
sui client publish --with-unpublished-dependencies --gas-budget 200000000
```

### Package Size Exceeded

**Error Message**:

```
Error: Package size (260 KB) exceeds maximum allowed size (250 KB)
```

**Cause**: Your package exceeds Sui's 250 KiB limit per package object. See [Sui transaction limits](https://move-book.com/guides/building-against-limits.html).

**Solutions**:

1. Split into multiple packages
2. Remove unused dependencies
3. Optimize data structures
4. Move large constants off-chain

**Example Split**:

```rust wrap theme={null}
// Package 1: Core logic
module my_oapp::core {
    // Essential functions
}

// Package 2: Utilities
module my_oapp::utils {
    // Helper functions
}
```

### Insufficient Gas for Deployment

**Error Message**:

```
Error: Insufficient gas: needed 150000000, available 100000000
```

**Cause**: Deployment requires more gas than budgeted.

**Solution**: Increase gas budget:

```bash wrap theme={null}
sui client publish --gas-budget 200000000
```

Deployment typically requires:

* Simple packages: 50-100M gas
* Complex packages: 100-200M gas
* With dependencies: 200M+ gas

### Upgrade Authority Issues

**Error Message**:

```
Error: UpgradeCap not found or not owned by signer
```

**Cause**: The signer doesn't own the `UpgradeCap` for the package.

**Solution**:

1. Verify you're using the correct account
2. Check UpgradeCap ownership:

```bash wrap theme={null}
sui client objects | grep UpgradeCap
```

3. Transfer UpgradeCap if needed

## Configuration Issues

### Channel Not Initialized

**Error Message**:

```
Error: Channel not initialized for endpoint ID 30101
```

**Cause**: Attempting to send message before initializing the messaging channel.

**Solution**: Initialize channel first:

```bash wrap theme={null}
sui client call \
    --package $PACKAGE \
    --module oapp \
    --function initialize_channel \
    --args $OAPP_OBJECT $ADMIN_CAP 30101 \
    --gas-budget 10000000
```

### Peer Not Set

**Error Message**:

```
Error: Peer address not configured for endpoint ID 30101
```

**Cause**: No peer OApp address configured for the destination chain.

**Solution**: Set peer address:

```bash wrap theme={null}
sui client call \
    --package $PACKAGE \
    --module oapp \
    --function set_peer \
    --args $OAPP_OBJECT $ADMIN_CAP 30101 $PEER_ADDRESS_BYTES \
    --gas-budget 10000000
```

**Address Format**: Ensure peer address is 32 bytes (pad EVM addresses).

### Library Configuration Missing

**Error Message**:

```
Error: Send library not configured for endpoint ID 30101
```

**Cause**: Custom library set but not properly configured.

**Solution**: Either:

1. Use default libraries (don't set custom)
2. Or properly configure custom library:

```bash wrap theme={null}
sui client call \
    --package $PACKAGE \
    --module oapp \
    --function set_send_library \
    --args $OAPP_OBJECT $ADMIN_CAP 30101 $LIBRARY_ADDRESS \
    --gas-budget 10000000
```

## Configuration Errors

### Peer Address Error (oapp\_registry abort)

**Error Message**:

```
Error: oapp_registry::get_messaging_channel abort code: 1
Error: MoveAbort in module oapp_registry
```

**Cause**: Remote chain is using wrong receiver address - likely using **object ID** instead of **package ID**.

**Solution**: On Sui, peer addresses must be **package IDs**, not object IDs.

**Find Your Correct Package ID**:

```bash wrap theme={null}
# Query your OApp/OFT object
sui client object <YOUR_OAPP_OBJECT_ID> --json | jq '.data.type'

# Output example:
# "0x061a47bffa630b8cd3735f8479edf7ab7897863fb3b796e77ebb8786af6f1bfc::oapp::OApp"
#  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#  This is your package ID - use as peer address!
```

**Update Peer on Remote Chain**:

```typescript wrap theme={null}
// On EVM/Solana/other chains, use Sui package ID:
await oapp.setPeer(
  30230, // Sui mainnet EID
  '0x061a47bffa630b8cd3735f8479edf7ab7897863fb3b796e77ebb8786af6f1bfc', // Package ID
);
```

**Why Package ID?**

* Sui OApps use `CapType::Package` for CallCap
* Registry and verification systems key by package address
* Object IDs are instance-specific, package ID is deployment-specific

### Package ID vs Object ID Confusion

**Error Message**:

```
Error: Transaction was not signed by the correct sender
Error: Object ID does not exist
```

**Cause**: Using package ID when object ID is required (or vice versa).

**Key Differences**:

* **Package ID**: Address of published code (immutable bytecode)
* **Object ID**: Address of object instance (mutable state)

**Example**:

```typescript wrap theme={null}
// - Wrong: Using package ID as object
tx.object(packageId); // Package is not an object!

// - Correct: Use object ID
tx.object(oappObjectId); // The OApp object instance
```

**How to Find**:

```bash wrap theme={null}
# View transaction outputs after publishing
sui client publish --json

# objectChanges array shows:
# - "published" type = package ID
# - "created" type = object IDs
```

### Invalid BCS Bytes Error

**Error Message**:

```
Error: InvalidBCSBytes
Error: Unable to deserialize config
Error: Failed to deserialize argument at index 6
```

**Cause**: Using `tx.pure()` instead of SDK's `asBytes()` helper for byte array parameters.

**Solution**: Use the SDK's `asBytes()` helper:

```typescript wrap theme={null}
import {SDK, OAppUlnConfigBcs} from '@layerzerolabs/lz-sui-sdk-v2';

// CRITICAL: Import asBytes helper
const {asBytes} = await import('@layerzerolabs/lz-sui-sdk-v2');

// Encode configuration
const config = OAppUlnConfigBcs.serialize({
  use_default_confirmations: false,
  use_default_required_dvns: false,
  use_default_optional_dvns: true,
  uln_config: {
    confirmations: 15,
    required_dvns: [dvnAddress],
    optional_dvns: [],
    optional_dvn_threshold: 0,
  },
}).toBytes();

const tx = new Transaction();

// - WRONG: Using tx.pure() causes InvalidBCSBytes
tx.pure(config, 'vector<u8>');

// - CORRECT: Use asBytes() helper
asBytes(tx, config);

// In context:
tx.moveCall({
  target: '...',
  arguments: [
    // ... other args
    asBytes(tx, config), // ← This works
  ],
});
```

**Why asBytes() is Required**:

The SDK's `asBytes()` function performs proper BCS vector wrapping:

```typescript wrap theme={null}
// Actual implementation from SDK utils/index.ts
export function asBytes(
  tx: Transaction,
  bytes: Uint8Array | TransactionArgument,
): TransactionArgument {
  if (isTransactionArgument(bytes)) {
    return bytes;
  }
  // Wraps in BCS vector encoding
  return tx.pure(bcs.vector(bcs.u8()).serialize(Array.from(bytes)).toBytes());
}
```

**What it does**:

* Takes raw bytes and wraps them in BCS vector format
* Handles Transaction Argument pass-through
* Ensures proper deserialization in Move's `vector<u8>` type

**Why `tx.pure()` fails**:

* Direct `tx.pure(bytes, 'vector<u8>')` doesn't apply BCS vector wrapping
* Move deserializer expects BCS-encoded vector format
* Results in `InvalidBCSBytes` error

**Common Scenarios Requiring asBytes()**:

* * DVN/ULN configuration
* * Execution options
* * OApp info parameters
* * Any `vector<u8>` config parameter

## Execution Errors

### Executor Transaction Fails (UnusedValueWithoutDrop)

**Error Message**:

```
Executor transaction simulation reverted
UnusedValueWithoutDrop { result_idx: 3, secondary_idx: 0 }
Error during lz_receive execution
```

**Cause**: Executor can't properly build the PTB to call your OApp/OFT's `lz_receive()` function.

**Most Common Reason for OFTs**: Missing or incorrect `lz_receive_info` during registration.

**Solution for OFTs**:

1. **Generate proper lz\_receive\_info**:

```typescript wrap theme={null}
const tx = new Transaction();
const [lzReceiveInfo] = tx.moveCall({
    target: `${oftPackage}::oft_ptb_builder::lz_receive_info`,
    typeArguments: [tokenType],
    arguments: [
        tx.object(oftObjectId),
        tx.object(endpointObjectId),
        tx.object('0xfbece0b75d097c31b9963402a66e49074b0d3a2a64dd0ed666187ca6911a4d12'),  // OFTComposerManager
        tx.object('0x6'),  // Clock
    ],
});

const result = await client.devInspectTransactionBlock({
    transactionBlock: tx,
    sender: yourAddress,
});
const lzReceiveInfoBytes = bcs.vector(bcs.u8()).parse(...);
```

2. **Update OApp info in registry**:

```typescript wrap theme={null}
import {asBytes} from '@layerzerolabs/lz-sui-sdk-v2';

const tx = new Transaction();
tx.moveCall({
  target: `${oappPackage}::endpoint_calls::set_oapp_info`,
  arguments: [
    tx.object(oappObjectId),
    tx.object(adminCapId),
    tx.object(endpointObjectId),
    asBytes(tx, oappInfoBytes), // Includes lz_receive_info
  ],
});

await client.signAndExecuteTransaction({transaction: tx});
```

**Prevention**: Always provide `lz_receive_info` during initial OFT registration (see [OFT Overview](/v2/developers/sui/oft/overview#registration-with-endpoint)).

### OApp Registry Error

**Error Message**:

```
Error: oapp_registry::get_messaging_channel abort code: 1
Error: MoveAbort in module oapp_registry
```

**Cause**: Remote chain is using wrong receiver address - using **object ID** instead of **package ID**.

**Solution**:

On Sui, peer addresses must be **package IDs**:

```bash wrap theme={null}
# Find your package ID
sui client object <YOUR_OAPP_OBJECT_ID> --json | jq '.data.type'
# Example: "0x061a47bf...::oapp::OApp"
#           ^^^^^^^^^^^^
# Use this package ID as peer on remote chains
```

Update peer on remote chain:

```solidity wrap theme={null}
// On EVM
oapp.setPeer(30230, bytes32(0x061a47bffa630b8cd3735f8479edf7ab7897863fb3b796e77ebb8786af6f1bfc));  // Package ID
```

**Why**: Sui uses Package CallCaps where `callCap.id()` returns the package address.

## Runtime Errors

### Call Object Not Consumed

**Error Message**:

```
Error: unused value without 'drop' ability
Error: unused value of type 'call::call::Call<...>'
```

**Cause**: A `Call` object was not properly consumed before the transaction ended.

**Root Causes**:

1. Missing confirmation call (e.g., `confirm_lz_send`)
2. PTB doesn't route the `Call` through all required modules
3. `Call` object created but never destroyed

**Solution**:

```rust wrap theme={null}
// - Incorrect: Call not confirmed
let call = oapp::send(&mut oapp, &call_cap, ...);
// Transaction ends → ERROR

// - Correct: Call confirmed and destroyed
let call = oapp::send(&mut oapp, &call_cap, ...);
// PTB processes the Call through Endpoint/ULN/Workers
let (params, receipt) = oapp::confirm_lz_send(&oapp, &call_cap, call);
```

**Debug Checklist**:

* [ ] Every `Call` creation has a corresponding confirm call
* [ ] PTB includes all required routing steps
* [ ] No early returns that skip confirmation
* [ ] All `Call` objects are destroyed before transaction ends

### Invalid Recipient

**Error Message**:

```
Error: Invalid recipient: object not owned by recipient address
```

**Cause**: Trying to send tokens to an invalid or non-existent address.

**Solution**:

1. Verify recipient address is valid
2. For token sends, check if recipient needs an account created
3. Ensure address format is correct (32 bytes)

### Gas Estimation Failures

**Error Message**:

```
Error: Unable to estimate gas for transaction
```

**Cause**: Transaction simulation failed during gas estimation.

**Solutions**:

1. Check transaction parameters are valid
2. Verify all required objects exist
3. Ensure signer has necessary permissions
4. Try with higher gas budget

**Debug**:

```bash wrap theme={null}
# Dry run to see simulation errors
sui client call ... --json --dry-run
```

## Transaction Issues

### PTB Construction Failures

**Error Message**:

```
Error: Invalid PTB: missing required call
```

**Cause**: Programmable Transaction Block doesn't include all required calls.

**Solution**: Verify PTB structure:

```typescript wrap theme={null}
// Correct PTB structure for send
const tx = new Transaction();

// 1. Call OApp
tx.moveCall({
  target: `${oappPackage}::oapp::send`,
  arguments: [
    /* ... */
  ],
});

// 2. PTB will route Hot Potatoes automatically
// 3. Confirm calls are added by the builder

await client.signAndExecuteTransaction({transaction: tx});
```

### Object Ownership Errors

**Error Message**:

```
Error: Object 0x... is not owned by sender
Error: InvalidObjectOwnership
```

**Cause**: Trying to use an owned object that belongs to a different address.

**Solutions**:

1. **Verify object ownership**:

```bash wrap theme={null}
sui client object <OBJECT_ID> --json | jq '.data.owner'
```

Output types:

* `{"AddressOwner": "0x..."}` - Owned by specific address
* `"Shared"` - Shared object (accessible to anyone)
* `"Immutable"` - Immutable object (read-only)

2. **Use correct signer**: Ensure the transaction signer owns the object

3. **Check object type**:
   * [**Owned objects**](https://docs.sui.io/concepts/object-ownership/address-owned) (`AdminCap`, `CallCap`): Must be owned by signer
   * [**Shared objects**](https://docs.sui.io/concepts/object-ownership/shared) (`OApp`, `EndpointV2`): Accessible by anyone, use references (`&` or `&mut`)
   * [**Immutable objects**](https://docs.sui.io/concepts/object-ownership/immutable) (`CoinMetadata`): Read-only references only

**Example**:

```rust wrap theme={null}
// - Correct: AdminCap owned by signer
public fun set_peer(
    oapp: &mut OApp,     // Shared object (anyone can reference)
    admin_cap: &AdminCap, // Owned object (must own to use)
    ...
)
```

### Storage Rebate Confusion

**Error Message** (not actually an error):

```
Gas used: -500000 (negative)
```

**Cause**: Transaction freed storage, resulting in a rebate.

**Explanation**: This is **normal behavior**, not an error. When storage is freed:

* You get a rebate for the freed storage
* Net gas cost can be negative
* Base budget of 1000 is still required

**Example**:

```rust wrap theme={null}
// Deleting object frees storage
let MyObject { id, data } = obj;
object::delete(id); // Triggers rebate
```

## SDK Errors

### Connection Timeout

**Error Message**:

```
Error: Request timeout: No response from RPC
```

**Cause**: RPC endpoint is slow or unresponsive.

**Solutions**:

1. Use a different RPC endpoint
2. Increase timeout:

```typescript wrap theme={null}
const client = new SuiClient({
  url: 'https://fullnode.mainnet.sui.io:443',
  timeout: 60000, // 60 seconds
});
```

3. Consider using a private RPC provider

### Invalid Object ID

**Error Message**:

```
Error: Invalid object ID format
```

**Cause**: Object ID is not properly formatted.

**Solution**: Ensure object IDs are 32-byte hex strings:

```typescript wrap theme={null}
// - Correct
const objectId = '0x1234...'; // 64 hex chars (32 bytes)

// - Incorrect
const objectId = '0x123'; // Too short
const objectId = '1234...'; // Missing 0x prefix
```

### Type Mismatch

**Error Message**:

```
Error: Type mismatch: expected '0x...::coin::Coin<0x...::token::TOKEN>', got '0x...::coin::Coin<0x2::sui::SUI>'
```

**Cause**: Wrong coin type passed to function.

**Solution**: Verify coin types match:

```typescript wrap theme={null}
// Check coin type
const coin = await client.getObject({id: coinId});
console.log('Coin type:', coin.data?.type);

// Use correct coin type
const result = await oft.send({
  tokenMint: '0x...::token::TOKEN', // Must match
  // ...
});
```

## Debugging Tips

### Enable Verbose Logging

```bash wrap theme={null}
# Sui CLI with verbose output
sui client call ... --json | jq .
```

### Check Transaction Effects

```typescript wrap theme={null}
const result = await client.signAndExecuteTransaction({
  transaction: tx,
  options: {
    showEffects: true,
    showEvents: true,
    showObjectChanges: true,
  },
});

console.log('Effects:', result.effects);
console.log('Events:', result.events);
console.log('Object changes:', result.objectChanges);
```

### Inspect Objects

```bash wrap theme={null}
# View object details
sui client object $OBJECT_ID --json

# View all objects for an address
sui client objects --json
```

### Use Sui Explorer

Navigate to [SuiScan](https://suiscan.xyz/) to:

* View transaction details
* Check object states
* Inspect event logs
* Verify package deployments

### Test on Devnet First

Always test on devnet before testnet/mainnet:

```bash wrap theme={null}
# Switch to devnet
sui client switch --env devnet

# Test your calls
sui client call ... --gas-budget 20000000
```

## Getting Help

If you continue to experience issues:

1. **Check Documentation**: Review [Sui Documentation](https://docs.sui.io/)
2. **Search Discord**: Look for similar issues in [LayerZero Discord](https://discord.com/invite/ktbvm8Nkcr)
3. **Ask for Help**: Post in Discord with:
   * Error message
   * Transaction hash (if available)
   * Code snippet
   * What you've tried

## Next Steps

* [FAQ](/v2/developers/sui/troubleshooting/faq)
* [Sui Guidance](/v2/developers/sui/technical-reference/sui-guidance)
* [Configuration Guide](/v2/developers/sui/configuration/dvn-executor-config)
* [Technical Overview](/v2/developers/sui/technical-overview)
