fish-shell/fish-shell · error

%s: expected a numeric value

Error message

%s: expected a numeric value

What it means

Raised by the printf builtin (src/builtins/printf.rs:219) in verify_numeric when nothing at all was consumed from the argument: the end slice still points at the start of s (s.as_ptr() == end.as_ptr()) and no converter error code was set. It means the argument to a numeric directive (%d, %f, %x, ...) does not begin with anything numeric. This is fatal: printf stops processing and exits with an error status.

Source

Thrown at src/builtins/printf.rs:219

impl<'a, 'b> State<'a, 'b> {
    #[allow(clippy::partialeq_to_none)]
    fn verify_numeric(&mut self, s: &wstr, end: &wstr, errcode: Option<wutil::Error>) {
        // This check matches the historic `errcode != EINVAL` check from C++.
        // Note that empty or missing values will be silently treated as 0.
        if errcode.is_some_and(|err| err != wutil::Error::InvalidChar && err != wutil::Error::Empty)
        {
            match errcode.unwrap() {
                wutil::Error::Overflow => {
                    self.fatal_error(err_fmt!("%s: Number out of range", s));
                }
                wutil::Error::InvalidChar | wutil::Error::Empty => {
                    unreachable!("Unreachable");
                }
            }
        } else if !end.is_empty() {
            if s.as_ptr() == end.as_ptr() {
                self.fatal_error(err_fmt!("%s: expected a numeric value", s));
            } else {
                // This isn't entirely fatal - the value should still be printed.
                self.nonfatal_error(err_fmt!(
                    "%s: value not completely converted (can't convert '%s')",
                    s,
                    end
                ));
                // Warn about octal numbers as they can be confusing.
                // Do it if the unconverted digit is a valid hex digit,
                // because it could also be an "0x" -> "0" typo.
                if s.char_at(0) == '0' && iswxdigit(end.char_at(0)) {
                    self.nonfatal_error(err_str!(
                        "Hint: a leading '0' without an 'x' indicates an octal number"
                    ));
                }
            }
        }
    }

View on GitHub (pinned to a1e92997a1)

Solutions

  1. Validate the value before printf: `string match -qr '^-?[0-9]+(\.[0-9]+)?$' -- $val` and reject/skip otherwise
  2. Use fish's `math` builtin or `read` with validation instead of printf numeric coercion for untrusted input
  3. Print untrusted data with %s and only use numeric directives for values your script produced
  4. Check the variable is set and non-empty first: empty values are silently treated as 0, which can mask upstream bugs

Example fix

# before
printf '%d' $maybe_number   # abc: expected a numeric value

# after
if string match -qr -- '^-?[0-9]+$' $maybe_number
    printf '%d' $maybe_number
else
    echo "not a number: $maybe_number" >&2
end
Defensive patterns

Strategy: validation

Validate before calling

# only hand provably-numeric strings to numeric directives
if string match -qr -- '^[+-]?[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?$' $value
    printf '%f\n' $value
else
    echo "skipping non-numeric: $value" >&2
end

Type guard

function is_numeric
    string match -qr -- '^[+-]?([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?$' $argv[1]
end

Prevention

When it happens

Trigger: Running `printf %d abc`, `printf %f NaN_variable`, or `printf %x 0x` where the parse consumes zero characters. Reached when errcode is None/InvalidChar/Empty but end is non-empty and unchanged; i.e. wcstoi_partial/wcstod returned consumed == 0 with no hard error. Note the leading-quote form `printf %f "'a"` bypasses this via from_ord.

Common situations: Unquoted or wrongly-parsed variables feeding printf format strings; scripts assuming an environment variable always holds a number; user input not validated; a subtle case is locale issues with decimal separators for %f, though fish retries with '.' before giving up (see the wcstod fallback in RawStringToScalarType).

Related errors


AI-assisted analysis of fish-shell/fish-shell@a1e92997a1 (2026-08-17). Data as JSON: /api/errors/2a7f15c3d7629968. Report an issue: GitHub.