babalae/better-genshin-impact · error · InvalidOperationException

意外的 token:{tokens[pos].Value}

Error message

意外的 token:{tokens[pos].Value}

What it means

Thrown by ConditionEvaluator.ParsePrimary as a catch-all when the token at the current parse position is none of: LParen, Identifier, Number, or Bool. This means the grammar encountered a token where a primary expression (value or sub-expression) was expected but got an operator or comma instead. When called via Evaluate(), this is caught internally and Evaluate returns false.

Source

Thrown at BetterGenshinImpact/GameTask/AutoFight/Script/ConditionEvaluator.cs:381

                pos++;
                return new FuncCallNode(name, args);
            }
            return new FuncCallNode(name, []);
        }

        if (tokens[pos].Type == TokenType.Number)
        {
            var val = double.Parse(tokens[pos].Value, CultureInfo.InvariantCulture); pos++;
            return new NumberNode(val);
        }

        if (tokens[pos].Type == TokenType.Bool)
        {
            var val = tokens[pos].Value == "true"; pos++;
            return new BoolNode(val);
        }

        throw new InvalidOperationException($"意外的 token:{tokens[pos].Value}");
    }

    // ========== AST 求值(统一返回 object: double 或 bool) ==========

    /// <summary>求值 AST 节点</summary>
    private object Eval(AstNode node, int currentIndex)
    {
        return node switch
        {
            BoolNode b => b.Value,
            NumberNode n => n.Value,
            UnaryOpNode u => EvalUnary(u, currentIndex),
            BinaryOpNode b => EvalBinary(b, currentIndex),
            FuncCallNode f => EvalFunc(f.Name, f.Args, currentIndex),
            _ => false
        };
    }

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Inspect the token value in the error message to identify what was unexpected.
  2. Ensure each operand position has a valid primary expression (identifier, number, bool, function call, or parenthesized group).
  3. Remove double operators or misplaced commas.
  4. Test the expression in isolation with logging enabled to trace the parse.

Example fix

// before (dangling operator)
"condition": "&& q-ready()"

// after
"condition": "q-ready()"
Defensive patterns

Strategy: try-catch

Try / catch

// Evaluate catches this internally (line 147-151) and returns false.
// To detect when a condition silently fails, wrap Evaluate with logging:
bool result;
try
{
    result = evaluator.Evaluate(expr, idx, name, action);
}
catch
{
    result = false; // Evaluate itself shouldn't throw, but be safe
}
Logger.LogDebug("条件 {Expr} => {Result}", expr, result);

Prevention

When it happens

Trigger: A malformed condition expression where an operator appears where a value is expected. For example: `&& q-ready()` (starts with operator), `q-ready(,)` (empty argument position), or `since()` followed immediately by a comma with no value. Also triggered by consecutive operators like `q-ready() && || low-hp()`.

Common situations: User writes a condition with a misplaced operator, empty argument, or dangling comma in a function call. Often from partial editing or incorrect copy-paste of expression fragments.

Related errors


AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13). Data as JSON: /api/errors/83169962f6882e1b. Report an issue: GitHub.