diff --git a/CHANGELOG.md b/CHANGELOG.md
index b8262f68..0ecd1756 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,10 @@ All notable changes to sem are documented in this file.
## [Unreleased]
+### Fixed
+
+- **Building a graph over Svelte components no longer crashes (SIGSEGV) on Linux/glibc.** `sem graph`/`context`/`orient` over `.svelte` files deterministically exited 139 from an invalid free in the `tree-sitter-htmlx-svelte` 0.1.8 grammar's scanner, hit during parallel graph construction (macOS's allocator tolerated the bad free, so it only showed on Linux). Bumped the grammar to 0.1.16, which carries the scanner fixes; the existing version constraint already permitted it, so this is a lock-only dependency update. Added a parallel-Svelte-graph regression test. Thanks @XF-FW for the exhaustive isolation and the verified fix (#471).
+
## [0.21.0] - 2026-07-10
### Added
diff --git a/crates/Cargo.lock b/crates/Cargo.lock
index ea86e8bf..48e3239e 100644
--- a/crates/Cargo.lock
+++ b/crates/Cargo.lock
@@ -2262,9 +2262,9 @@ dependencies = [
[[package]]
name = "tree-sitter-htmlx-svelte"
-version = "0.1.8"
+version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3259693b6c5f6a7044de1a8142507aa1950406a4b124ffaab28c9050e30973dd"
+checksum = "f3278db98d220cb32e1d82510036740786c817afc1224b3360658f499224e63c"
dependencies = [
"cc",
"tree-sitter",
diff --git a/crates/sem-core/tests/graph_accuracy.rs b/crates/sem-core/tests/graph_accuracy.rs
index cd3d3d6f..dd7f57e9 100644
--- a/crates/sem-core/tests/graph_accuracy.rs
+++ b/crates/sem-core/tests/graph_accuracy.rs
@@ -201,3 +201,73 @@ fn graph_accuracy_rust() {
);
assert!(tp > 0, "Should find at least some expected edges");
}
+
+/// Regression for issue #471: building a graph over multiple Svelte components
+/// in parallel triggered a SIGSEGV (invalid free) in the
+/// tree-sitter-htmlx-svelte 0.1.8 grammar's scanner on Linux/glibc. Fixed by
+/// bumping the grammar to 0.1.16. On macOS the bad free was tolerated by the
+/// allocator, so this only fails on Linux/glibc CI; everywhere it at least
+/// exercises the parallel Svelte parse path that used to crash.
+#[test]
+fn graph_svelte_parallel_no_crash_issue_471() {
+ let tmp = tempfile::tempdir().unwrap();
+ let root = tmp.path();
+
+ for args in [
+ vec!["init"],
+ vec!["config", "user.email", "test@test.com"],
+ vec!["config", "user.name", "Test"],
+ ] {
+ std::process::Command::new("git")
+ .args(&args)
+ .current_dir(root)
+ .output()
+ .unwrap();
+ }
+
+ // Enough components that the parallel (rayon) graph build parses several
+ // .svelte files concurrently, which is where the grammar crashed.
+ let component = r#"
+
+
+
+
+"#;
+ let mut files = Vec::new();
+ for i in 0..12 {
+ let name = format!("Component{i}.svelte");
+ std::fs::write(root.join(&name), component).unwrap();
+ files.push(name);
+ }
+
+ std::process::Command::new("git")
+ .args(["add", "."])
+ .current_dir(root)
+ .output()
+ .unwrap();
+ std::process::Command::new("git")
+ .args(["commit", "-m", "init"])
+ .current_dir(root)
+ .output()
+ .unwrap();
+
+ let registry = create_default_registry();
+ // Reaching past this call at all means no SIGSEGV during parallel parsing.
+ let (graph, _) = EntityGraph::build(root, &files, ®istry);
+
+ // Sanity: the components were actually parsed, not silently skipped.
+ assert!(
+ graph.entities.values().any(|e| e.name == "handleLogoClick"),
+ "expected handleLogoClick entity from parsed .svelte components"
+ );
+}