babalae/better-genshin-impact · error · InvalidOperationException

JavaScript没有设置Output输出

Error message

JavaScript没有设置Output输出

What it means

Thrown by IsMatchJavaScript after engine.Execute(javaScript) succeeds but engine.Script.propertyIsEnumerable('Output') returns false. ClearScript exposes host/global properties through engine.Script; the user's JS must assign a global 'Output' variable. Its absence means the script never set a result.

Source

Thrown at BetterGenshinImpact/GameTask/AutoArtifactSalvage/AutoArtifactSalvageTask.cs:485

                engine.Interrupt();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"中断失败: {ex.Message}");
            }
        });
        try
        {
            // 传入输入参数
            engine.Script.ArtifactStat = artifact;

            // 执行JavaScript代码
            await Task.Run(() => engine.Execute(javaScript));

            // 检查是否有输出
            if (!engine.Script.propertyIsEnumerable("Output"))
            {
                throw new InvalidOperationException("JavaScript没有设置Output输出");
            }

            if (engine.Script.Output is not bool)
            {
                throw new InvalidOperationException("JavaScript的Output输出不是布尔类型");
            }

            return (bool)engine.Script.Output;
        }
        catch (ScriptInterruptedException)
        {
            logger.LogWarning("脚本执行超出3秒限制,请使用正确的JS代码(JavaScript execution timeout!)");
            throw;
        }
        catch (ScriptEngineException ex)
        {
            throw new Exception($"JavaScript execution error: {ex.Message}", ex);
        }

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Ensure the JS sets a top-level 'var Output = ...;' or 'Output = ...;' (no let/const inside a block).
  2. Confirm the assignment runs unconditionally on the last line, after all logic.
  3. Test the JS in isolation with the same ArtifactStat input.
  4. Document that Output must be a global boolean and provide a template script.

Example fix

// before (user JS)
function decide(a) { return a.level >= 20; }
// (Output never set globally)
// after
function decide(a) { return a.level >= 20; }
Output = decide(ArtifactStat); // top-level global, boolean
Defensive patterns

Strategy: validation

Validate before calling

bool HasGlobalOutput(string js) => Regex.IsMatch(js, @"(^|[^\w.])Output\s*=", RegexOptions.Multiline);

Try / catch

try { return await IsMatchJavaScript(artifact, js, logger); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Output"))
{ logger.LogError("JS 未设置全局 Output 布尔输出"); throw; }

Prevention

When it happens

Trigger: User JS declared Output inside a function scope or as a const in a module (not global); JS threw before reaching the assignment (but Execute did not surface it); script used 'let Output' which ClearScript may not expose as enumerable; script assigned to a misspelled name (e.g. 'output').

Common situations: Custom artifact-filter JS authored without reading the Output contract; JS ported from Node where module-scope vars are global; ClearScript V8 flag differences (DisableGlobalMembers is set, so only explicit globals are visible).

Related errors


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