nautechsystems/nautilus_trader · error

Execution transaction {} has no signed payload

Error message

Execution transaction {} has no signed payload

What it means

When preparing a transaction for submission, the code checks that the hash row has `payload_expected = true`, meaning a signed transaction payload must exist. If the flag is set but no signed payload was actually produced/attached, the transaction cannot be encoded and submission aborts. This is a pipeline consistency check between payload production and hash bookkeeping.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:3619

    let mut current = hashes.iter().filter(|row| row.current);
    let row = current
        .next()
        .ok_or_else(|| anyhow::anyhow!("Execution intent {intent_id} has no current hash"))?;
    anyhow::ensure!(
        current.next().is_none(),
        "Execution intent {intent_id} has more than one current hash"
    );
    Ok(row)
}

fn open_execution_payload(
    keys: &PayloadKeySet,
    policy: PayloadPolicy,
    intent: &ExecutionIntentRow,
    hash: &ExecutionTransactionHashRow,
    reason: &str,
) -> anyhow::Result<Vec<u8>> {
    anyhow::ensure!(
        hash.payload_expected,
        "Execution transaction {} has no signed payload",
        hash.transaction_hash
    );
    anyhow::ensure!(
        hash.raw_transaction.is_none(),
        "Protected execution transaction {} contains plaintext",
        hash.transaction_hash
    );
    let envelope = hash.sealed_transaction.as_deref().ok_or_else(|| {
        anyhow::anyhow!(
            "Protected execution transaction {} has no sealed payload",
            hash.transaction_hash
        )
    })?;
    let context = payload_context(intent, hash, keys.deployment_id())?;
    let raw_transaction = keys.unseal(envelope, &context)?;
    log::info!(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Re-run the signing step for this transaction hash so a signed payload is produced and persisted before submission.
  2. If the transaction legitimately has no signed payload, correct the row's payload_expected flag (or the upstream logic setting it) to match reality.
  3. Check signer/keystore configuration and credentials, since signer failure is the usual root cause of the missing payload.
  4. Replay the pipeline from the intent stage to regenerate the row and payload together.

Example fix

// before: row written before signing completed
store.record_hash(row_with_payload_expected_true)?;

// after: persist the signed payload first, or set the flag only when it exists
let signed = signer.sign(unsigned_tx)?;
row.raw_or_sealed_payload = Some(signed);
row.payload_expected = true;
store.record_hash(row)?;
Defensive patterns

Strategy: validation

Validate before calling

if hash.payload_expected && hash.raw_transaction.is_none() && hash.sealed_transaction.is_none() {
    // re-sign or fail before invoking payload resolution
    anyhow::bail!("tx {} missing signed payload; re-run signing", hash.transaction_hash);
}

Type guard

fn has_payload(hash: &ExecutionTransactionHashRow) -> bool {
    !hash.payload_expected || hash.raw_transaction.is_some() || hash.sealed_transaction.is_some()
}

Try / catch

match resolve_payload(keys, policy, intent, hash, reason) {
    Ok(bytes) => submit(bytes),
    Err(e) if e.to_string().contains("no signed payload") => retry_after_resign(intent, hash),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling the payload-resolution function with a hash row whose `payload_expected` is true but whose signed payload (raw/envelope data) was never persisted — e.g. the signing step failed silently or the row was written before the payload arrived.

Common situations: Signer service down or unreachable when the intent was recorded; a crash between writing the hash row and persisting the signed payload; stale rows from a partially completed run; misconfigured payload policy that skips signing while the row still claims a payload is expected.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/558acdfc49e2e280. Report an issue: GitHub.