elsa-workflows/elsa-core · error · InvalidOperationException

Variable ' ' is not declared. Use 'var ' to declare a new…

Error message

Variable '{forNode.VariableName}' is not declared. Use 'var {forNode.VariableName}' to declare a new variable in the for loop.

What it means

CompileForAsync reuses an existing declared variable as the for-loop counter; if forNode.VariableName was never declared with 'var', the compiler throws InvalidOperationException with a message suggesting the 'var' declaration. Like foreach, the for statement does not implicitly declare its loop variable.

Solutions

  1. Declare the counter before the loop: var i; then for (i = 0; i < 10; i += 1) { ... }.
  2. Ensure the declared name matches the loop variable exactly.
  3. If the parser supports an inline declaration form, use it so the variable is created by the loop itself.
  4. Catch the exception and surface a hint to declare the loop variable.

Example fix

// before
for (i = 0; i < 10; i += 1) { } // i undeclared
// after
var i;
for (i = 0; i < 10; i += 1) { }
Defensive patterns

Strategy: validation

Validate before calling

const declared = collectVarDeclarations(ast); const missing = collectForVars(ast).filter(v => !declared.has(v.name)); if (missing.length) throw new Error('Declare with var: ' + missing.map(m => m.name).join(', '));

Type guard

function forVarsDeclared(ast) { const declared = declaredVarNames(ast); return ast.forNodes.every(n => declared.has(n.variableName)); }

Try / catch

try { await compileScript(script); } catch (InvalidOperationException ex) when (ex.Message.Contains('is not declared')) { showDeclareVarFix(ex); }

Prevention

When it happens

Trigger: A for statement whose VariableName is absent from the compiler's _variables dictionary when the 'else' reuse path is taken (no inline declaration provided).

Common situations: C-style habits (for (i = 0; ...)) without declaring i, a typo between declaration and loop usage, or the variable declared in an enclosing scope the compiler's variable table does not include.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/4409832110dc5c0d. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Dsl.ElsaScript/Compiler/ElsaScriptCompiler.cs:308

        return forEachActivity;
    }

    private async Task<IActivity> CompileForAsync(ForNode forNode, CancellationToken cancellationToken = default)
    {
        Variable loopVariable;

        if (forNode.DeclaresVariable)
        {
            // Create a new loop variable
            loopVariable = new Variable<int>(forNode.VariableName, 0);
            _variables[forNode.VariableName] = loopVariable;
        }
        else
        {
            // Reuse existing variable
            if (!_variables.TryGetValue(forNode.VariableName, out loopVariable!))
            {
                throw new InvalidOperationException($"Variable '{forNode.VariableName}' is not declared. Use 'var {forNode.VariableName}' to declare a new variable in the for loop.");
            }
        }

        var start = CompileExpressionAsInput<int>(forNode.Start);
        var end = CompileExpressionAsInput<int>(forNode.End);
        var step = CompileExpressionAsInput<int>(forNode.Step);
        var body = await CompileStatementAsync(forNode.Body, cancellationToken);

        var forActivity = new For
        {
            Start = start,
            End = end,
            Step = step,
            OuterBoundInclusive = new Input<bool>(forNode.IsInclusive),
            CurrentValue = new Output<object?>(loopVariable),
            Body = body
        };

View on GitHub (pinned to fe9217bdfa)