slint-ui/slint · info

Failed to serialize ()!

Error message

Failed to serialize ()!

What it means

After successfully applying a populate/creation-data edit, the LSP handler for `populate_command` returns `Ok(serde_json::to_value(()).expect("Failed to serialize ()!"))`, serializing the unit type as the JSON response. Unit type serialization is infallible in serde_json, so this expect is a tautological internal invariant; it can practically never fire and is not a real failure mode developers can trigger.

Solutions

  1. If it ever fires, verify the serde_json version and features match what slint-lsp was built against (no exotic feature flags).
  2. Replace the expect with `serde_json::Value::Null` or `.unwrap_or(serde_json::Value::Null)` to remove the unreachable panic path.
  3. Rebuild the LSP with a stock toolchain if a patched serde tree is in use.

Example fix

// before
Ok(serde_json::to_value(()).expect("Failed to serialize ()!"))

// after
Ok(serde_json::Value::Null)
Defensive patterns

Strategy: try-catch

Try / catch

// Not reachable in practice; if patching:
match serde_json::to_value(()) {
    Ok(v) => Ok(v),
    Err(e) => Err(LspError { code: LspErrorCode::RequestFailed, message: format!("serialize failed: {e}") }),
}

Prevention

When it happens

Trigger: In theory: serde_json being built with `arbitrary_precision`/`no_std`-style alloc feature configurations that alter serialization behavior; in practice, never under default features.

Common situations: Not observed in real usage; a panic here would indicate a broken/modified serde_json build rather than a user mistake.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of slint-ui/slint@bb937076de (2026-09-16). Data as JSON: /api/errors/aa7621db4eb0a37f. Report an issue: GitHub.

Appendix: source

Thrown at tools/lsp/language.rs:797

            )
            .map_err(|_| LspError {
                code: LspErrorCode::RequestFailed,
                message: "Failed to send populate edit".into(),
            })?
            .await
            .map_err(|_| LspError {
                code: LspErrorCode::RequestFailed,
                message: "Failed to send populate edit".into(),
            })?;

        if !response.applied {
            return Err(LspError {
                code: LspErrorCode::RequestFailed,
                message: "Failed to apply population edit".into(),
            });
        }

        Ok(serde_json::to_value(()).expect("Failed to serialize ()!"))
    })
}

/// Synchronous step in the host-language rename flow: classify the
/// declaration the user just renamed, and -- if it is exposed in the
/// generated Rust/C++ public API and the rename actually changes the
/// accessor name -- spawn the async dialog + scanner + applyEdit follow-up.
///
/// The handler that calls this has already returned the slint-only
/// `WorkspaceEdit` synchronously, so by the time the dialog appears the
/// `.slint` file has already been updated by the client. The host-language
/// scanner runs against the *old* accessor name on disk and produces a
/// second `workspace/applyEdit` from the spawned task; the editor's
/// undo/redo treats the two edits independently. That is intentional: if
/// the user rejects the host-language rewrite (or the scanner errors),
/// the slint rename still stands.
#[cfg(not(target_arch = "wasm32"))]
fn schedule_host_language_rename_followup(

View on GitHub (pinned to bb937076de)