bevyengine/bevy · error · ParseError

expected an identifier, got '{0}' instead

Error message

expected an identifier, got '{0}' instead

What it means

This nested ParseError variant ExpectedIdent reports that the parser found a token where an identifier was required: it includes the offending token. It happens when a segment starts with something that is not an identifier — a number, ']', '[', '.', etc. — e.g. accessing tuple/struct elements by '.'-index instead of bracket syntax.

Source

Thrown at crates/bevy_reflect/src/path/parse.rs:21

    num::ParseIntError,
    str::from_utf8_unchecked,
};
use thiserror::Error;

use super::{Access, ReflectPathError};

/// An error that occurs when parsing reflect path strings.
#[derive(Debug, PartialEq, Eq, Error)]
#[error(transparent)]
pub struct ParseError<'a>(Error<'a>);

/// A parse error for a path string.
#[derive(Debug, PartialEq, Eq, Error)]
enum Error<'a> {
    #[error("expected an identifier, but reached end of path string")]
    NoIdent,

    #[error("expected an identifier, got '{0}' instead")]
    ExpectedIdent(Token<'a>),

    #[error("failed to parse index as integer")]
    InvalidIndex(#[from] ParseIntError),

    #[error("a '[' wasn't closed, reached end of path string before finding a ']'")]
    Unclosed,

    #[error("a '[' wasn't closed properly, got '{0}' instead")]
    BadClose(Token<'a>),

    #[error("a ']' was found before an opening '['")]
    CloseBeforeOpen,
}

pub(super) struct PathParser<'a> {
    path: &'a str,
    remaining: &'a [u8],

View on GitHub (pinned to 396ca72708)

Solutions

  1. Replace dot-then-index with bracket syntax: "foo.0" becomes "foo[0]".
  2. Ensure each segment begins with a valid identifier (letter/underscore, then alphanumerics/underscore).
  3. Prefix numeric-named fields if the type genuinely has such names, or index them via brackets when they are tuple elements.
  4. Inspect the token in the error message to see exactly what the parser saw.

Example fix

// before
let x = tuple_struct.path::<f32>("fields.0"); // ExpectedIdent: got '0'

// after
let x = tuple_struct.path::<f32>("fields[0]");
Defensive patterns

Strategy: try-catch

Validate before calling

fn starts_with_ident_seg(p: &str) -> bool {
    p.split('.').all(|seg| seg.chars().next().is_some_and(|c| c.is_alphabetic() || c == '_'))
}

Try / catch

match entity.reflect_path(path_str) {
    Ok(el) => { /* ... */ }
    Err(ReflectPathError::ParseError { offset, path, error }) => {
        // error names the offending token, e.g. got '0'
        warn!("'{path}' has a non-name token at {offset}: {error}");
    }
    Err(other) => warn!("path failed: {other}"),
}

Prevention

When it happens

Trigger: Paths like "foo.0" (index written after a dot — must be "foo[0]"), "0.foo" (leading digit), or tokens like "foo.]" where a field name was expected; the message shows the exact bad token.

Common situations: Developers used to tuple-access syntax (tuple.0) applying it to reflect paths; concatenating segments that start with digits; copy-paste from JSONPath/JS expressions into reflect path strings.

Related errors


AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20). Data as JSON: /api/errors/9c05b4647150bfbb. Report an issue: GitHub.