BigPizzaV3/CodexPlusPlus · warning
throw new Error( );
Error message
throw new Error({}); What it means
In codex-plus-core's build_enabled_bundle, each enabled user script file is read with fs::read_to_string. If reading a script file fails (missing file, permission denied, invalid UTF-8, IO error), the reader does not abort the bundle build; instead it substitutes a JavaScript stub `throw new Error("...");` as the script body, embedding the Rust IO error message. This means the generated bundle will raise this error in the JS runtime whenever that script executes, surfacing the file-read failure at script-run time rather than bundle-build time.
Solutions
- Locate the failing script from the embedded error message and either recreate the file at its configured path or disable/remove it from the script list.
- Re-save the script file as UTF-8 (read_to_string fails on invalid UTF-8).
- Fix file permissions on the script file so the process user can read it.
- If you want build-time detection instead of runtime throws, change the code to fail the scan (propagate the io::Error with `?`) or log a warning and skip disabled/broken scripts.
Example fix
// before: silent stub that throws at script runtime
let source = fs::read_to_string(&script.path)
.unwrap_or_else(|error| format!("throw new Error({});", json!(error.to_string())));
// after: propagate the failure at bundle-build time
let source = fs::read_to_string(&script.path)
.map_err(|error| anyhow!("failed to read script {:?}: {}", script.path, error))?; Defensive patterns
Strategy: validation
Validate before calling
for script in &scripts {
if script.enabled && !script.path.exists() {
eprintln!("warning: enabled script missing: {:?}", script.path);
}
if script.enabled && !script.path.is_file() {
// exclude from bundle or fail fast
}
} Type guard
fn readable_utf8_script(path: &Path) -> bool {
path.is_file() && fs::read(path).map(|bytes| std::str::from_utf8(&bytes).is_ok()).unwrap_or(false)
} Try / catch
// Rust has no try/catch; wrap the bundle build and surface the substituted runtime error
match build_enabled_bundle(&config) {
Ok(bundle) => install(bundle),
Err(e) => eprintln!("脚本包构建失败: {e}"),
}
// at runtime, catch the injected throw
try { runUserScript(source); } catch (e) { console.error("脚本文件读取失败:", e.message); } Prevention
- Disable or delete script entries in the config as soon as the underlying file is removed.
- Save scripts as UTF-8 without BOM; avoid editors that write UTF-16.
- Keep script files inside the project/user directory; avoid fragile symlinked locations.
- Run a script-directory health check (exists + readable) before applying the bundle.
When it happens
Trigger: Calling build_enabled_bundle (via the apply/scan script pipeline) while an enabled script's path no longer exists, is unreadable due to permissions, or contains invalid UTF-8 bytes.
Common situations: User deleted or renamed a script file but left it marked enabled in the scripts config; scripts directory moved or synced incompletely between machines; a symlink pointing to a removed target; a non-UTF8 (e.g. UTF-16 or GBK) script file saved by a Windows editor.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- 无法启动 Codex app-server(
- archived lookup task failed
- built-in Dream Skin theme cannot be deleted
- built-in Dream Skin theme is read-only
- cannot terminate Windows process id
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/d990726001621a2d.
Report an issue: GitHub.
Appendix: source
Thrown at crates/codex-plus-core/src/user_scripts.rs:246
"enabled": config.enabled,
"builtin_dir": self.builtin_dir.to_string_lossy(),
"user_dir": self.user_dir.to_string_lossy(),
"scripts": scripts
}))
}
pub fn build_enabled_bundle(&self) -> anyhow::Result<String> {
let config = self.load_config();
if !config.enabled {
return Ok(String::new());
}
let mut blocks = Vec::new();
for script in self.scan_script_files(&config)? {
if !script.enabled {
continue;
}
let source = fs::read_to_string(&script.path)
.unwrap_or_else(|error| format!("throw new Error({});", json!(error.to_string())));
blocks.push(wrap_script(&script, &source));
}
Ok(blocks.join("\n"))
}
fn scan_scripts(
&self,
config: &UserScriptConfig,
runtime_status: Option<&Value>,
) -> anyhow::Result<Vec<Value>> {
let runtime_scripts = runtime_status
.and_then(|value| value.get("scripts").or(Some(value)))
.and_then(Value::as_object);
Ok(self
.scan_script_files(config)?
.into_iter()
.map(|script| {
let market = config.market.get(&script.key);View on GitHub (pinned to b1ed92e5e4)