FuelLabs/sway · error

{e}

Error message

{e}

What it means

After stripping 0x, HexSalt::from_str delegates to fuel_tx::Salt::from_str, which demands exactly 64 hex characters (the 32-byte Salt type). This pass-through error fires for wrong-length or non-hex bodies - the message is the underlying fuel-tx error verbatim. It is the second of the two salt parse failures (the first being the missing-0x check one line above).

Source

Thrown at forc-pkg/src/manifest/mod.rs:271

#[serde(rename_all = "kebab-case")]
pub struct Network {
    #[serde(default = "default_url")]
    pub url: String,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct HexSalt(pub fuel_tx::Salt);

impl FromStr for HexSalt {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        // cut 0x from start.
        let normalized = s
            .strip_prefix("0x")
            .ok_or_else(|| anyhow::anyhow!("hex salt declaration needs to start with 0x"))?;
        let salt: fuel_tx::Salt =
            fuel_tx::Salt::from_str(normalized).map_err(|e| anyhow::anyhow!("{e}"))?;
        let hex_salt = Self(salt);
        Ok(hex_salt)
    }
}

impl Display for HexSalt {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let salt = self.0;
        write!(f, "{salt}")
    }
}

fn default_hex_salt() -> HexSalt {
    HexSalt(fuel_tx::Salt::default())
}

#[serde_as]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]

View on GitHub (pinned to 47e5e902fa)

Solutions

  1. Use exactly 64 hex characters after 0x (32 bytes).
  2. For the zero salt write 0x followed by 64 zeros, or omit the salt to get the default.
  3. Verify programmatically: the string after 0x must have len 64 and contain only [0-9a-fA-F].

Example fix

# before
salt = "0x1234"

# after
salt = "0x0000000000000000000000000000000000000000000000000000000000001234"
Defensive patterns

Strategy: validation

Validate before calling

// Rust, full salt-shape check before parsing:
fn valid_salt(s: &str) -> bool {
    match s.strip_prefix("0x") {
        Some(body) => body.len() == 64 && body.chars().all(|c| c.is_ascii_hexdigit()),
        None => false,
    }
}

Type guard

// Type-guard style predicate usable as a gate:
fn is_complete_hex_salt(s: &str) -> bool {
    let b = s.as_bytes();
    b.len() == 66 && b[0]==b'0' && b[1]==b'x'
        && b[2..].iter().all(|c| c.is_ascii_hexdigit())
}

Try / catch

// anyhow Result - surface the fuel-tx message (it names length/hex problems):
match HexSalt::from_str(salt_str) {
    Ok(s) => s,
    Err(e) => { eprintln!("invalid salt body: {e}; need 64 hex chars after 0x"); return; }
}

Prevention

When it happens

Trigger: A salt like 0xdeadbeef (too short), 0x plus more/fewer than 64 hex chars, or containing non-hex characters (g-z, punctuation) inside a contract-dependency salt field or CLI --salt value.

Common situations: Short placeholder salts (0x0); copying truncated salts; mixed-in checksum characters that are not hex; line-wrapping in editors splitting the salt string.

Related errors


AI-assisted analysis of FuelLabs/sway@47e5e902fa (2026-08-16). Data as JSON: /api/errors/39c680b1d16174bb. Report an issue: GitHub.