stride3d/stride · error · LexerException

Cannot read from

Error message

Cannot read from {getName()}

What it means

Preprocessor's InternalSource.token() always throws LexerException("Cannot read from <internal-data>"): the internal source exists only to supply directives (e.g. pragma/state data) and has no tokens of its own. If the token stream ever tries to pull a token from it, the preprocessor's source stack is in an invalid state.

Solutions

  1. Ensure every push_source(InternalSource, ...) is paired with pop_source before requesting the next token.
  2. Stop calling token()/tok() once the real source is exhausted (check for end-of-input instead of reading again).
  3. Pass a real LexerSource (backed by the shader file/reader) to the Preprocessor rather than relying on internal data alone.
  4. Install a PreprocessorListener to catch the earlier directive error that left the source stack unbalanced.

Example fix

// before: reading tokens after the internal source was pushed
pp.push_source(new Preprocessor.InternalSource(), false);
// ... forgot to pop ...
var t = pp.token(); // LexerException: Cannot read from <internal-data>
// after
pp.push_source(new Preprocessor.InternalSource(), false);
// ... directive work ...
pp.pop_source();
var t = pp.token();
Defensive patterns

Strategy: try-catch

Validate before calling

// Check a real source is active before pulling tokens
if (preprocessor.getCurrentSource() is Preprocessor.InternalSource)
    preprocessor.pop_source();

Type guard

bool RealSourceActive(Preprocessor pp) => pp.getCurrentSource() is not Preprocessor.InternalSource;

Try / catch

try
{
    var tok = preprocessor.token();
}
catch (LexerException ex) when (ex.Message.Contains("Cannot read from"))
{
    throw new InvalidOperationException("Token requested with no active input source (unbalanced push_source/pop_source)", ex);
}

Prevention

When it happens

Trigger: Calling preprocessor.token()/tok() (or processing a pragma) when the current source on the stack is the InternalSource — i.e. all real input sources have been popped but tokenization continues, or push_source(InternalSource) was used without a subsequent pop before the next token request.

Common situations: Unbalanced push_source/pop_source around #include handling or pragma processing; continuing to call tok() after the real lexer source hit EOF; misusing the internal API to feed data without providing a real LexerSource.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

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

`1'
    This indicates the start of a new file.
`2'
    This indicates returning to a file (after having included another
    file).
`3'
    This indicates that the following text comes from a system header
    file, so certain warnings should be suppressed.
`4'
    This indicates that the following text should be treated as being
    wrapped in an implicit extern "C" block.
*/

internal class Preprocessor : IDisposable {
    private class InternalSource : Source {
        public override Token token()
        {
			throw new LexerException("Cannot read from " + getName());
		}

        internal override String getPath()
        {
			return "<internal-data>";
		}
		
		internal override String getName() {
			return "internal data";
		}
    }

	private static readonly Source		INTERNAL = new InternalSource();
    private static readonly Macro		__LINE__ = new Macro(INTERNAL, "__LINE__");
	private static readonly Macro		__FILE__ = new Macro(INTERNAL, "__FILE__");
	private static readonly Macro		__COUNTER__ = new Macro(INTERNAL, "__COUNTER__");

	private List<Source>			inputs;

View on GitHub (pinned to 96fad776d2)