linera-io/linera-protocol · error

RegisterFungibleBridge requires an authenticated signer

Error message

RegisterFungibleBridge requires an authenticated signer

What it means

RegisterFungibleBridge is an owner-only operation: the contract calls runtime.authenticated_owner() and expects Some, which Linera only returns when the transaction executing this operation is signed by the owner of the bridge chain. A panic aborts the entire transaction, so bridge_contract_address is never set. This is the intended authorization gate for binding the bridge to an EVM contract address.

Source

Thrown at linera-bridge/contracts/evm-bridge/src/contract.rs:95

                )
                .await;
            }
            BridgeOperation::VerifyBlockHash { block_hash } => {
                self.verify_block_hash(block_hash).await;

                // Only cache when called by an authenticated signer (chain owner),
                // preventing unauthenticated callers from bloating state.
                if self.runtime.authenticated_owner().is_some() {
                    self.state
                        .verified_block_hashes
                        .insert(&block_hash)
                        .expect("failed to insert verified block hash");
                }
            }
            BridgeOperation::RegisterFungibleBridge { address } => {
                self.runtime
                    .authenticated_owner()
                    .expect("RegisterFungibleBridge requires an authenticated signer");
                assert!(
                    self.state.bridge_contract_address.get().is_none(),
                    "bridge contract address is already registered and cannot be changed"
                );
                self.state.bridge_contract_address.set(Some(address));
            }
            BridgeOperation::SetRpcEndpoint { rpc_endpoint } => {
                self.runtime
                    .authenticated_owner()
                    .expect("SetRpcEndpoint requires an authenticated signer");
                self.validate_rpc_endpoint(&rpc_endpoint).await;
                self.state.rpc_endpoint.set(rpc_endpoint);
            }
            BridgeOperation::Burn { amount, evm_target } => {
                self.initiate_burn(amount, evm_target);
            }
        }
    }

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Submit the operation from a client that signs the block with the bridge chain owner's key
  2. Verify wallet ownership before deploying (e.g. linera wallet show / your client's signing config) and confirm you are targeting the bridge chain ID
  3. If you maintain the contract, prefer assert!(authenticated_owner().is_some(), ...) so the rejection message is a clean transaction failure
  4. Re-check that no middleware/session wrapper strips the owner signature from the transaction

Example fix

// before (contract panics, whole transaction aborts)
self.runtime
    .authenticated_owner()
    .expect("RegisterFungibleBridge requires an authenticated signer");

// after (clean rejection, same semantics)
let Some(_owner) = self.runtime.authenticated_owner() else {
    panic!("RegisterFungibleBridge requires an authenticated signer");
};
// Caller-side fix: submit the operation in an owner-signed block —
// linera process-and-transfer --signer <owner-key> <bridge-chain> ...
Defensive patterns

Strategy: validation

Validate before calling

// Before submitting, confirm the client will sign as the bridge chain owner:
let owner = wallet.owner_of(bridge_chain_id).expect("not the owner of bridge chain");
assert_eq!(owner, signer.public());
client.submit(bridge_chain_id, BridgeOperation::RegisterFungibleBridge { address });

Type guard

// Rust narrowing helper for contract code:
fn require_authenticated_owner(runtime: &mut impl ContractRuntime)
    -> Result<Owner, &'static str>
{
    runtime.authenticated_owner().ok_or("RegisterFungibleBridge requires an authenticated signer")
}

Try / catch

// Linera transactions abort atomically on panic; there is nothing to catch
// client-side beyond the failed transaction. Check the failure reason and
// re-sign the operation with the owner key before resubmitting.

Prevention

When it happens

Trigger: Submitting RegisterFungibleBridge in a block signed by any key other than the bridge-chain owner; invoking the operation through another application's session (session calls carry no authenticated signer); deploying from a wallet whose default account is not the chain owner; targeting the wrong chain ID.

Common situations: Deployment scripts that authenticate as a service or CI account; test harnesses with freshly generated keys submitting to a bridge chain created by a different wallet; misconfigured linera client where the owner key is not loaded.

Understand the failure class

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/16fb9d21d6de4107. Report an issue: GitHub.