fish-shell/fish-shell · error

%s

Error message

%s

What it means

When a `function` definition statement fails, run_function_statement runs the function builtin, captures its exit status and any text written to the error stream, and re-raises the builtin's message through report_error! using the format string '%s' with the captured error text. The '%s' is the error's format template, not the actual message; the real diagnostic (e.g. 'function: name should be one word') is in errtext.

Source

Thrown at src/parse_execution.rs:1319

            return result;
        }

        trace_if_enabled_with_args(ctx.parser(), L!("function"), &arguments);
        let mut outs = OutputStream::Null;
        let mut errs = OutputStream::String(StringOutputStream::new());
        let io_chain = IoChain::new();
        let mut streams = IoStreams::new(&mut outs, &mut errs, &io_chain);
        let mut shim_arguments: Vec<&wstr> = arguments
            .iter()
            .map(|s| truncate_at_nul(s.as_ref()))
            .collect();
        let err_code = builtins::function::function(
            ctx.parser(),
            &mut streams,
            &mut shim_arguments,
            NodeRef::new(Arc::clone(self.pstree()), statement),
        )
        .err()
        .unwrap_or(STATUS_CMD_OK);

        ctx.parser().libdata_mut().status_count += 1;
        ctx.parser().set_last_statuses(Statuses::just(err_code));

        let errtext = errs.contents();
        if !errtext.is_empty() {
            report_error!(self, ctx, err_code, header, "%s", errtext);
        }
        result
    }

    fn run_begin_statement(
        &mut self,
        ctx: &mut OperationContext<'_>,
        contents: &ast::JobList,
    ) -> EndExecutionReason {
        // Basic begin/end block. Push a scope block, run jobs, pop it

View on GitHub (pinned to edb719d76c)

Solutions

  1. Read the accompanying diagnostic line printed with this error for the actual cause
  2. Ensure the function name is a single valid word (letters/digits/underscore, not starting with a dash, no path separators)
  3. If the name comes from a variable, quote and validate it before `function $name`, e.g. `function $name; ...` only when `string match -qr '^[A-Za-z_][A-Za-z0-9_]*$' -- $name`
  4. Check that all arguments on the function header line expand correctly and don't contain wildcards that match nothing

Example fix

// before
function $fname; echo hi; end  # fname empty -> error
// after
if set -q fname[1]; and string match -qr '^[A-Za-z_][A-Za-z0-9_]*$' -- $fname
    function $fname; echo hi; end
end
Defensive patterns

Strategy: try-catch

Validate before calling

if not string match -qr '^[A-Za-z_][A-Za-z0-9_]*$' -- $fname
    echo "invalid function name: $fname" >&2
    exit 1
end

Type guard

function is_valid_function_name
    string match -qr '^[A-Za-z_][A-Za-z0-9_]*$' -- $argv[1]
end

Try / catch

// fish has no try/catch for parse errors; capture and inspect status
function define_fn --argument-names name
    eval "function $name; end" 2>/tmp/fnerr
    or begin
        cat /tmp/fnerr >&2
        return 1
    end
end

Prevention

When it happens

Trigger: Executing a `function NAME ...; end` statement where the function builtin returns an error status: invalid function name (not a valid identifier / contains slashes), duplicate reserved names, missing name, or arguments failing expansion.

Common situations: Sourcing an old script whose function name collides with fish's reserved/invalid names, `function` with a variable-expanded name that expands to an empty string or multiple words, or copy-pasted zsh/bash function syntax invalid in fish.

Related errors


AI-assisted analysis of fish-shell/fish-shell@edb719d76c (2026-09-03). Data as JSON: /api/errors/a0155814d16289bd. Report an issue: GitHub.