stride3d/stride · error · LexerException

Error at

Error message

Error at {line}:{column}: {msg}

What it means

Preprocessor.error reports preprocessing errors (raised from error, warning, pop_state, include) at a given line/column. When a PreprocessorListener is installed, the error is delegated to listener.handleError; with no listener, it throws LexerException("Error at line:column: msg") instead. It is the central funnel for directive-level failures such as failed #include or bad directives.

Solutions

  1. Install a PreprocessorListener (implementing handleError/handleWarning) so diagnostics are collected instead of thrown at the first problem.
  2. Fix the reported source location: check the file at the given line:column — for includes, verify the path and the include search paths passed to the Preprocessor.
  3. Correct the malformed preprocessor directive (#define, #if, #pragma) flagged by the message.
  4. Wrap preprocessing in try-catch on LexerException and surface line/column information to the user.

Example fix

// before: no listener, first directive error throws
var pp = new Preprocessor();
pp.addIncludePath("shaders");
// after: listener collects errors, preprocessing completes
var pp = new Preprocessor();
pp.setListener(new CollectingListener(errors));
pp.addIncludePath("shaders");
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check includes and directives before preprocessing
foreach (var inc in Regex.Matches(src, @"#\s*include\s*[\"<]([^\">]+)"))
    if (!ResolveOnIncludePaths(inc.Groups[1].Value, includePaths, out _))
        report($"Include not found: {inc.Groups[1].Value}");

Try / catch

var errors = new List<Diagnostic>();
try
{
    preprocessor.setListener(new CollectingListener(errors));
    while ((tok = preprocessor.token()) != null) { /* ... */ }
}
catch (LexerException ex)
{
    errors.Add(Diagnostic.Parse(ex.Message)); // "Error at L:C: msg"
}

Prevention

When it happens

Trigger: Any preprocessing error with no listener installed: a failed #include (file not found), malformed directives, state errors in pop_state, or error()-reported conditions during pragma handling.

Common situations: #include of a shader file whose path is wrong or not in the include search paths; syntax errors in #if/#define expressions; parsing shader sources with a Preprocessor configured without a listener so every warning-level issue escalates to an exception.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/b48e06630deed3b5. Report an issue: GitHub.

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/CppNet/Preprocessor.cs:278

	 *
	 * @see #addInput(Source)
	 */
	public void addInput(FileInfo file) {
		addInput(new FileLexerSource(file));
	}


	/**
	 * Handles an error.
	 *
	 * If a PreprocessorListener is installed, it receives the
	 * error. Otherwise, an exception is thrown.
	 */
	protected void error(int line, int column, String msg) {
		if (listener != null)
			listener.handleError(source, line, column, msg);
		else
			throw new LexerException("Error at " + line + ":" + column + ": " + msg);
	}

	/**
	 * Handles an error.
	 *
	 * If a PreprocessorListener is installed, it receives the
	 * error. Otherwise, an exception is thrown.
	 *
	 * @see #error(int, int, String)
	 */
	protected void error(Token tok, String msg) {
		error(tok.getLine(), tok.getColumn(), msg);
	}

	/**
	 * Handles a warning.
	 *
	 * If a PreprocessorListener is installed, it receives the

View on GitHub (pinned to 96fad776d2)