swc-project/swc · error

failed to parse the value of DecimalLiteral

Error message

failed to parse the value of DecimalLiteral

What it means

Thrown while converting an ESTree DecimalLiteral into swc's Number node (swc_estree_compat `swcify`). The `value` string is parsed with Rust's `f64::from_str`, which accepts only standard float syntax (digits, optional '.', exponent, optional sign, inf/NaN); the `.expect(...)` panics on any other content. ESTree decimal-proposal literals keep the 'm' suffix in their textual value (e.g. "1.1m"), which f64 parsing rejects, as do 'n' BigInt suffixes, whitespace, and empty strings.

Source

Thrown at crates/swc_estree_compat/src/swcify/lit.rs:161

                .parse()
                .map(Box::new)
                .expect("failed to parse the value of BigIntLiteral"),
            // TODO improve me
            raw: None,
        }
    }
}

impl Swcify for DecimalLiteral {
    type Output = Number;

    fn swcify(self, ctx: &Context) -> Self::Output {
        Number {
            span: ctx.span(&self.base),
            value: self
                .value
                .parse()
                .expect("failed to parse the value of DecimalLiteral"),
            // TODO improve me
            raw: None,
        }
    }
}

View on GitHub (pinned to 5176682b65)

Solutions

  1. Normalize the value before converting: strip a trailing 'm' (and any 'n' or separators) so the string is a plain decimal number
  2. If you generate the ESTree AST yourself, emit value as a plain numeric string like "1.1"
  3. Filter/validate DecimalLiteral nodes before running swcify and surface a proper error instead of a panic
  4. Patch the crate to use a fallible parse and report the value in a diagnostic

Example fix

// before
// node = { type: 'DecimalLiteral', value: '1.1m' }
swcify(node); // panics: failed to parse the value of DecimalLiteral

// after
node.value = node.value.replace(/[mn]$/, ''); // '1.1'
swcify(node);
Defensive patterns

Strategy: validation

Validate before calling

function decimalValueOk(node) {
  if (node.type !== 'DecimalLiteral') return true;
  const v = String(node.value).replace(/[mn]$/, '');
  return v !== '' && !Number.isNaN(Number(v));
}
const bad = nodes.filter(n => !decimalValueOk(n));
if (bad.length) throw new Error(`unparseable DecimalLiteral value: ${bad[0].value}`);

Type guard

function isParseableDecimalLiteral(node: unknown): boolean {
  if (typeof node !== 'object' || node === null) return false;
  const n = node as { type?: string; value?: unknown };
  if (n.type !== 'DecimalLiteral') return false;
  if (typeof n.value !== 'string') return false;
  const v = n.value.replace(/[mn]$/, '');
  return v !== '' && !Number.isNaN(Number(v));
}

Try / catch

// Rust: convert the panic into an error at the boundary
let out = std::panic::catch_unwind(|| ast.swcify(&ctx))
    .map_err(|_| anyhow::anyhow!("DecimalLiteral value failed to parse; check for 'm' suffix"));

Prevention

When it happens

Trigger: Calling `.swcify(ctx)` on a tree containing a DecimalLiteral whose `value` is not parseable as f64: value="1.1m", value="0.3m", value="10n", value="", or value with whitespace/thousand separators.

Common situations: Converting ASTs from parsers that support the (withdrawn) JS decimal proposal and leave the 'm' suffix in value; mixing BigInt values into decimal nodes; hand-crafted fixtures; lossy JSON round-trips that empty the value field.

Understand the failure class

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/d0c51ab8504622bc. Report an issue: GitHub.