nautechsystems/nautilus_trader · error

Deployment manifest is missing a swap call graph

Error message

Deployment manifest is missing a swap call graph

What it means

After per-edge validation, the manifest must contain at least one call edge with purpose "swap_sell" and at least one with purpose "swap_buy". A deployment without both swap directions cannot be used for the router's two-way swap flow, so validation fails with this error.

Source

Thrown at crates/adapters/blockchain/src/rpc/verification.rs:1422

        for address in [caller, target] {
            anyhow::ensure!(
                contract_addresses.contains(&address),
                "Call edge references an unpinned contract"
            );
        }
        anyhow::ensure!(
            call_edges.insert((
                edge.purpose.as_str(),
                caller,
                target,
                edge.call_type.as_str()
            )),
            "Deployment manifest contains a duplicate call edge"
        );
    }

    for purpose in ["swap_sell", "swap_buy"] {
        anyhow::ensure!(
            manifest
                .call_edges
                .iter()
                .any(|edge| edge.purpose == purpose),
            "Deployment manifest is missing a swap call graph"
        );
    }
    Ok(())
}

fn validate_identity(identity: &BlockchainProviderIdentity) -> anyhow::Result<()> {
    anyhow::ensure!(
        !identity.provider_id.trim().is_empty(),
        "Provider ID is required"
    );
    anyhow::ensure!(
        !identity.operator_id.trim().is_empty(),
        "Provider operator ID is required"

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Add call edges with purpose "swap_sell" and "swap_buy" from the router to the swap-capable contract
  2. If your generator supports a swap-flow option, enable it so both directions are emitted
  3. Restore the swap edges from a previously valid manifest for the same deployment
  4. Verify after editing that call_edges contains at least one edge of each required purpose

Example fix

// before
{"call_edges": [{"purpose": "wrap", ...}, {"purpose": "approve", ...}]}
// after
{"call_edges": [{"purpose": "wrap", ...}, {"purpose": "approve", ...}, {"purpose": "swap_sell", "caller": "0xrouter...", "target": "0xpool...", "call_type": "call"}, {"purpose": "swap_buy", "caller": "0xrouter...", "target": "0xpool...", "call_type": "call"}]}
Defensive patterns

Strategy: validation

Validate before calling

for purpose in ["swap_sell", "swap_buy"] {
    if !manifest.call_edges.iter().any(|e| e.purpose == purpose) {
        return Err(format!("manifest missing a '{purpose}' call edge"));
    }
}

Try / catch

match validate_deployment_manifest(&manifest) {
    Err(e) if e.to_string().contains("missing a swap call graph") => {
        eprintln!("Add both swap_sell and swap_buy call edges to the manifest");
    }
    Err(e) => return Err(e),
    Ok(()) => {}
}

Prevention

When it happens

Trigger: Validating a manifest whose call_edges only include "wrap"/"approve" edges (or only one swap direction); this fires even when every individual edge is valid and pinned.

Common situations: Authoring a minimal manifest with just approval edges and forgetting the swap graph; a generator configured for one-directional swaps only; accidentally deleting the swap edges while trimming an existing manifest; copying a template where swap edges were removed as examples.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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