Skip to content

No way to raise a fatal error with a custom message: no throw/raise/fail, no stderr channel, no settable exit code #703

Description

@logbie

Summary

There is no way for a WFL program to fail on purpose with its own message. No throw/raise/fail keyword exists, there is no stderr channel, and the process exit code cannot be set — so a program that detects a fatal condition can only print to stdout and then deliberately trigger an unrelated runtime error to get a nonzero status.

Reproduction

The behaviour a program wants (PHP: throw new \RuntimeException('Unclosed string at position: ' . $pos)):

store pos as 42
display "jshrink: Unclosed string at position: " with pos
store fatal as 1 divided by 0

Command:

wfl g3_fatal.wfl

Expected

A documented way to abort with a program-supplied message and a nonzero exit
status — something in the shape of raise "Unclosed string at position: " with pos.

No documentation citation exists — filed as a capability gap, not a broken
runtime. Docs/03-language-basics/error-handling.md documents catching
comprehensively (try at :5, finally at :135, error_message at :192,
typed when <error type> clauses at :260) but never documents raising. Every
error in the docs originates in the runtime. There is no throw/raise/fail
token among the 181 reserved keywords
(Docs/reference/reserved-keywords.md), and no such function in the 190-entry
native registry.

Actual

The catching half works exactly as documented — this is confirmed, not a
complaint. Errors raised inside nested actions propagate, error_message binds,
finally runs, and execution continues:

trying
caught: Division by zero
cleanup ran
continued

The raising half has no form. The closest achievable behaviour is above, which
gives:

jshrink: Unclosed string at position: 42

on stdout, exit code 1, plus the runtime's own unrelated
Runtime errors: ... error[ERROR]: Division by zero on stderr and — unless
debug_report_enabled = false is set in .wflcfg — a <script>_debug.txt
dropped into the current working directory.

Three separate things are missing:

  1. no way to construct an error with a custom message;
  2. no way to write to stderr (both display and print go to stdout via
    emit_line, src/stdlib/core.rs:15);
  3. no way to set the exit code (and exit/exit program do not terminate the
    program at all — filed separately).

Consequence: a CLI written in WFL cannot report a clean diagnostic. It either
exits 0 after printing an error (looks like success to a shell or CI) or exits 1
with a misleading runtime message attached to a line that has nothing to do with
the real failure.

Environment

  • wfl --version: WebFirst Language (WFL) version 26.8.4
  • binary: system install C:\Program Files\wfl\bin\wfl.exe
  • commit: c277d8f
  • OS: Windows 11 Pro 10.0.26200
  • build: release

Also reproduces on the repo build (26.8.2). No .wflcfg in scope for the repro.

Context

Found while porting G:/repos/JShrink/src/JShrink/Minifier.php (a 738-line PHP
JavaScript minifier) to WFL. JShrink raises four distinct fatal errors with
position-bearing messages (Unclosed string at position: N,
Unclosed multiline comment at position: N, Unclosed regex pattern at position: N,
Unclosed character class at position: N), and minify() catches to run cleanup
before rethrowing.

This one shaped the port's CLI contract: the catch/cleanup structure ported
cleanly onto try / when error / finally, but the four throws became
"print the message, then force a division by zero," which is what is in the port
today. It works — message visible, exit nonzero — and it is not stubbed, but it is
a workaround standing in for a missing primitive, and the misleading
Division by zero on stderr is a real wart for anyone reading CI output.

Note this is a natural companion to the exit issue: a raise statement plus a
working program-terminating exit would together close the whole CLI story.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions