FuelLabs/sway · error

hex salt declaration needs to start with 0x

Error message

hex salt declaration needs to start with 0x

What it means

HexSalt::from_str requires salt strings to begin with the literal prefix 0x, which is stripped before delegating the remainder to fuel_tx::Salt::from_str. This specific error covers only the missing-prefix case; a present-but-malformed body produces the follow-on error instead. It surfaces wherever salts are parsed from text: contract-dependency salt fields in Forc.toml and the forc add --salt path.

Source

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

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[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())
}

View on GitHub (pinned to 47e5e902fa)

Solutions

  1. Prefix the value with 0x: salt = "0x<64 hex>".
  2. Copy salts from Forc.lock, which always prints them 0x-prefixed via the Display impl directly below this code.
  3. When in doubt omit the salt and let the default zero salt apply.

Example fix

# before (Forc.toml)
[contract-dependencies]
auth = { git = "...", salt = "deadbeef0000..." }

# after
[contract-dependencies]
auth = { git = "...", salt = "0xdeadbeef000000000000000000000000000000000000000000000000000000" }
Defensive patterns

Strategy: validation

Validate before calling

// Rust, enforce the 0x prefix before parsing a salt string:
fn has_0x_prefix(s: &str) -> bool { s.trim().starts_with("0x") }

Try / catch

// anyhow Result from HexSalt::from_str; distinguish prefix vs body failure:
match HexSalt::from_str(s) {
    Err(e) if e.to_string().contains("needs to start with 0x") =>
        eprintln!("prefix the salt with 0x"),
    Err(e) => eprintln!("salt body invalid: {e}"),
    Ok(salt) => salt,
}

Prevention

When it happens

Trigger: A salt value without 0x - e.g. salt = "abcdef..." under [contract-dependencies] in Forc.toml, or --salt 0000... on the command line - being parsed into a HexSalt.

Common situations: Copying a bare-hex salt from a block explorer or another tool; hand-writing manifest entries modeled on other hex fields; scripts generating salts without the prefix.

Related errors


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