{"record":{"id":"ece834d5dc366af2","repo":"slint-ui/slint","slug":"e","errorCode":null,"errorMessage":"{e:?}","messagePattern":"\\{e:\\?\\}","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"tools/lsp/wasm_main.rs","lineNumber":480,"sourceCode":"            .handle_request(method, params, &mut ctx)\n            .map_err(|e| JsError::new(&e.to_string()))?;\n        Ok(result)\n    }\n\n    #[wasm_bindgen]\n    pub async fn reload_config(&self) -> JsResult<()> {\n        let mut ctx = self.ctx.lock().await;\n        language::load_configuration(&mut ctx).await.map_err(|e| JsError::new(&e.to_string()))\n    }\n}\n\nasync fn load_file(path: String, load_file: &Function) -> std::io::Result<String> {\n    let string_promise = load_file\n        .call1(&JsValue::UNDEFINED, &path.into())\n        .map_err(|x| std::io::Error::new(ErrorKind::Other, format!(\"{x:?}\")))?;\n    let string_future = wasm_bindgen_futures::JsFuture::from(js_sys::Promise::from(string_promise));\n    let js_value =\n        string_future.await.map_err(|e| std::io::Error::new(ErrorKind::Other, format!(\"{e:?}\")))?;\n    return Ok(js_value.as_string().unwrap_or_default());\n}\n\n// Use a JSON friendly representation to avoid using ES maps instead of JS objects.\nfn to_value<T: serde::Serialize + ?Sized>(\n    value: &T,\n) -> std::result::Result<wasm_bindgen::JsValue, serde_wasm_bindgen::Error> {\n    value.serialize(&serde_wasm_bindgen::Serializer::json_compatible())\n}\n","sourceCodeStart":462,"sourceCodeEnd":490,"githubUrl":"https://github.com/slint-ui/slint/blob/bb937076de3f7919766c1f25e2e969367cf77e9a/tools/lsp/wasm_main.rs#L462-L490","documentation":"After the `load_file` JS callback returns a Promise, the LSP awaits it as a JsFuture; if the promise resolves to a rejection (the file could not actually be read by the browser), the rejection JsValue is Debug-formatted into a std::io::Error. This is thrown because awaiting the file-load promise is mandatory to produce the source text the compiler needs. The Debug form loses the human-readable JS error message.","triggerScenarios":"The injected JS `load_file` function's returned Promise rejects: fetch returned non-2xx (mapped to rejection), network failure, the callback threw asynchronously, or resolved with a non-string that downstream handling turns into a failure.","commonSituations":"404/CORS on the served file in the browser, WebSocket-based file service disconnecting, a Promise polyfill mismatch in older browsers, or the host page's `load_file` rejecting because the path is outside the served virtual filesystem.","solutions":["Open the browser devtools console to read the actual rejection reason hidden behind the debug-formatted JsValue.","Ensure the JS callback rejects only on real errors and resolves with a UTF-8 string for success (stringify Blobs/ArrayBuffers before returning).","Fix file serving: correct path mapping, MIME/permissions, and CORS so the fetch inside `load_file` succeeds.","Add retry/backoff in the host JS `load_file` for transient network failures.","Upgrade wasm-bindgen/wasm-bindgen-futures consistently in the LSP build if JsFuture conversion is involved in the failure."],"exampleFix":"// before (host JS)\nconst load_file = (path) => fetch(path).then(r => r.arrayBuffer());\n// after\nconst load_file = async (path) => {\n  const res = await fetch(path);\n  if (!res.ok) throw new Error(`HTTP ${res.status} for ${path}`);\n  return res.text();\n};","handlingStrategy":"retry","validationCode":"// JS host side: ensure the endpoint is reachable before init\nconst probe = await fetch(basePath + '/health');\nif (!probe.ok) throw new Error('file server unavailable');","typeGuard":"// JS host side: only resolve with strings\nfunction asText(v) { return typeof v === 'string' ? v : Promise.reject(new Error('load_file must resolve to a string')); }","tryCatchPattern":"const load_file = async (path) => {\n  for (let attempt = 0; attempt < 3; attempt++) {\n    try {\n      const res = await fetch(path);\n      if (res.status >= 500 || res.status === 0) throw new Error('transient');\n      if (!res.ok) throw new Error(`HTTP ${res.status}`);\n      return await res.text();\n    } catch (e) {\n      if (attempt === 2) throw e;\n      await new Promise(r => setTimeout(r, 500 * 2 ** attempt));\n    }\n  }\n};","preventionTips":["Resolve the promise with a UTF-8 string, never raw ArrayBuffer/Blob.","Add retry with backoff for transient network errors in the JS callback.","Map HTTP status codes to descriptive Error messages before rejecting.","Verify CORS/preflight configuration for the file endpoints.","Keep wasm-bindgen and wasm-bindgen-futures versions in sync."],"tags":["wasm","javascript","promise","lsp","file-loading"],"backgroundTag":"file-read-failed","analyzedSha":"bb937076de3f7919766c1f25e2e969367cf77e9a","analyzedAt":"2026-09-16T01:37:20.251Z","contentChangedAt":"2026-09-16T01:37:20.251Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}