{"record":{"id":"eac481b94ff91853","repo":"sinelaw/fresh","slug":"js-error-in-quickjs-backend","errorCode":null,"errorMessage":"JS error in {}: {}","messagePattern":"JS error in (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fresh-plugin-runtime/src/backend/quickjs_backend.rs","lineNumber":428,"sourceCode":"\n                if !stack.is_empty() {\n                    return anyhow::anyhow!(\n                        \"JS error in {}: {}: {}\\nStack trace:\\n{}\",\n                        source_name,\n                        name,\n                        message,\n                        stack\n                    );\n                } else {\n                    return anyhow::anyhow!(\"JS error in {}: {}: {}\", source_name, name, message);\n                }\n            } else {\n                // Exception is not an object, try to convert to string\n                let exc_str: String = exc\n                    .as_string()\n                    .and_then(|s: &rquickjs::String| s.to_string().ok())\n                    .unwrap_or_else(|| format!(\"{:?}\", exc));\n                return anyhow::anyhow!(\"JS error in {}: {}\", source_name, exc_str);\n            }\n        }\n    }\n\n    // Fall back to the basic error message\n    anyhow::anyhow!(\"JS error in {}: {}\", source_name, err)\n}\n\n/// Log a JavaScript error with full details\n/// If panic_on_js_errors is enabled, this will panic to surface JS errors immediately\n/// A JS expression reading `name` off `globalThis`, as a quoted key.\n///\n/// Handler names are strings a plugin chose, and plugin ids routinely carry\n/// characters that are not JS identifiers — every Finder-based plugin\n/// registers handlers like `_finder_git-grep_preview_tick`. Interpolated\n/// after a dot, that name is not a lookup but an expression (`git` minus\n/// `grep_preview_tick`), and the call dies with a ReferenceError naming a\n/// function nobody wrote. Quoting the key makes any name work, including","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-plugin-runtime/src/backend/quickjs_backend.rs#L410-L446","documentation":"Formatting step of format_js_error for QuickJS exceptions that carry a non-empty stack trace: it produces an anyhow error embedding the source name, error name, message, and full stack. It fires whenever a JS exception propagates out of evaluated plugin code (uncaught throw, runtime TypeError, explicit Error thrown by the plugin) and the engine attached trace info; exceptions without a stack take the shorter message-only branch. log_js_error and execute_js use the result to report the plugin failure.","triggerScenarios":"Plugin code throws a non-Error value such as a string, number, or object (e.g. throw \"oops\") during execute_js; the value cannot be converted to a JS string so it is Debug-formatted.","commonSituations":"Plugins throwing raw strings or numbers instead of Error objects; third-party plugin code with unconventional throw patterns.","solutions":["Change the plugin to throw Error objects instead of primitives so messages are readable","Inspect the coerced value in the message to identify the throw site","Wrap plugin entry points in try/catch that converts thrown values to Errors"],"exampleFix":"// before\nthrow 42;\n// after\nthrow new Error('failed with code 42');","handlingStrategy":"try-catch","validationCode":"// static check: no bare 'throw <non-Error>' in plugin sources\ngrep -nE \"throw\\s+(['\\\"0-9{])\" plugin.js","typeGuard":null,"tryCatchPattern":"match backend.execute_js(src) {\n    Err(e) if e.to_string().contains(\"JS error in\") => {\n        log::warn!(\"plugin threw a non-Error value: {e}\");\n        disable_plugin();\n    }\n    other => other,\n}","preventionTips":["Enforce an ESLint rule (no-throw-literal) in plugin codebases","Wrap third-party plugin entry points to normalize thrown values into Errors","Review plugin code for raw throw statements","Add CI tests that exercise plugin error paths"],"tags":["javascript","quickjs"],"backgroundTag":"unexpected-response-shape","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}