Skip to content

Troubleshooting

This guide covers common issues and their solutions when working with TypeGraph.

”Cannot find module ‘@nicia-ai/typegraph’”

Section titled “”Cannot find module ‘@nicia-ai/typegraph’””

Cause: Package not installed or using wrong package name.

Solution:

Terminal window
npm install @nicia-ai/typegraph zod drizzle-orm

Cause: Native module compilation requires build tools.

Solutions:

macOS:

Terminal window
xcode-select --install

Ubuntu/Debian:

Terminal window
sudo apt-get install build-essential python3

Windows:

Terminal window
npm install --global windows-build-tools

Alternative: Use sql.js for pure JavaScript SQLite (no compilation needed).

”Module not found: drizzle-orm/better-sqlite3”

Section titled “”Module not found: drizzle-orm/better-sqlite3””

Cause: Drizzle ORM subpath exports require specific import syntax.

Solution: Ensure correct imports:

// Correct
import { drizzle } from "drizzle-orm/better-sqlite3";
// Incorrect
import { drizzle } from "drizzle-orm";

”Node schema contains reserved property names”

Section titled “”Node schema contains reserved property names””

Cause: Using reserved keys (id, kind, meta) in your Zod schema.

Solution: Rename your properties:

// Bad - 'id' is reserved
const User = defineNode("User", {
schema: z.object({
id: z.string(), // Error!
name: z.string(),
}),
});
// Good - use a different name
const User = defineNode("User", {
schema: z.object({
externalId: z.string(),
name: z.string(),
}),
});

TypeGraph automatically provides id, kind, and meta on all nodes.

”Edge type already has constraints defined”

Section titled “”Edge type already has constraints defined””

Cause: Defining from/to constraints on both the edge type and graph registration.

Solution: Define constraints in one place only:

// Option 1: On the edge type (reusable across graphs)
const worksAt = defineEdge("worksAt", {
from: [Person],
to: [Company],
});
const graph = defineGraph({
edges: {
worksAt: { type: worksAt }, // No from/to here
},
});
// Option 2: On the graph (flexible per-graph)
const worksAt = defineEdge("worksAt");
const graph = defineGraph({
edges: {
worksAt: { type: worksAt, from: [Person], to: [Company] },
},
});

Cause: Data doesn’t match the Zod schema.

Solution: Check the error details for specific issues:

try {
await store.nodes.Person.create({ name: "" });
} catch (error) {
if (error instanceof ValidationError) {
console.log(error.details.issues); // Zod issues array
}
}

Cause: Attempting to read/update/delete a non-existent node.

Solution: Check if the node exists first or handle the error:

const node = await store.nodes.Person.getById(someId);
if (!node) {
// Handle missing node
}
// Or use error handling
try {
await store.nodes.Person.update(someId, { name: "New" });
} catch (error) {
if (error instanceof NodeNotFoundError) {
console.log(`Node ${error.details.id} not found`);
}
}

Cause: Attempting to delete a node that has edges, with onDelete: "restrict" (the default).

Solution: Either delete the edges first or use a different delete behavior:

// Option 1: Delete edges first
const edges = await store.edges.worksAt.findFrom(person);
for (const edge of edges) {
await store.edges.worksAt.delete(edge.id);
}
await store.nodes.Person.delete(person.id);
// Option 2: Use cascade delete in schema
const graph = defineGraph({
nodes: {
Person: { type: Person, onDelete: "cascade" },
},
});

Cause: Creating a node with an ID that’s already used by a disjoint type.

Solution: Ensure IDs are unique across disjoint types or don’t use explicit IDs:

// If Person and Organization are disjoint:
// Bad - same ID for different types
await store.nodes.Person.create({ name: "Alice" }, { id: "entity-1" });
await store.nodes.Organization.create({ name: "Acme" }, { id: "entity-1" }); // Error!
// Good - let TypeGraph generate unique IDs
await store.nodes.Person.create({ name: "Alice" });
await store.nodes.Organization.create({ name: "Acme" });

Cause: Using the same alias twice in a query.

Solution: Use unique aliases:

// Bad
store.query()
.from("Person", "p")
.traverse("knows", "e")
.to("Person", "p") // Error! 'p' already used
// Good
store.query()
.from("Person", "p1")
.traverse("knows", "e")
.to("Person", "p2")

Causes and solutions:

  1. Type mismatch: Ensure you’re querying the correct node type

    // Check the node type name matches exactly
    .from("Person", "p") // Must match defineNode("Person", ...)
  2. Missing includeSubClasses: When querying a superclass

    .from("Content", "c", { includeSubClasses: true })
  3. Strict predicate: Check your filters aren’t too restrictive

    // Debug by removing filters temporarily
    const all = await store.query().from("Person", "p").select((c) => c.p).execute();
    console.log(all.length); // How many total?

Solutions:

  1. Use the query profiler:

    import { QueryProfiler } from "@nicia-ai/typegraph/profiler";
    const profiler = new QueryProfiler();
    profiler.attachToStore(store);
    // Run your queries...
    const report = profiler.getReport();
    console.log(report.recommendations);
  2. Add indexes based on profiler recommendations:

    import { defineNodeIndex } from "@nicia-ai/typegraph/indexes";
    const nameIndex = defineNodeIndex("Person", ["name"]);
  3. Limit results:

    .limit(100)
    // Or use pagination
    .paginate({ first: 20 })

Cause: Multiple processes accessing the same SQLite file without WAL mode.

Solution: Enable WAL mode:

const sqlite = new Database("myapp.db");
sqlite.pragma("journal_mode = WAL");

Cause: Too many concurrent connections.

Solution: Configure pool limits:

import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20, // Adjust based on your needs
idleTimeoutMillis: 30000,
});

“relation ‘typegraph_nodes’ does not exist”

Section titled ““relation ‘typegraph_nodes’ does not exist””

Cause: Migration not run.

Solution: Run the migration SQL:

// PostgreSQL
import { generatePostgresMigrationSQL } from "@nicia-ai/typegraph/postgres";
await pool.query(generatePostgresMigrationSQL());
// SQLite
import { generateSqliteMigrationSQL } from "@nicia-ai/typegraph/sqlite";
sqlite.exec(generateSqliteMigrationSQL());

”Extension not found” / “vector type not available”

Section titled “”Extension not found” / “vector type not available””

Cause: Vector extension not installed.

PostgreSQL:

CREATE EXTENSION IF NOT EXISTS vector;

SQLite:

import * as sqliteVec from "sqlite-vec";
sqliteVec.load(sqlite); // Must be called before creating backend

Cause: Query embedding has different dimension than stored embeddings.

Solution: Use consistent embedding dimensions:

// Schema defines 1536 dimensions
const Document = defineNode("Document", {
schema: z.object({
embedding: embedding(1536),
}),
});
// Query embedding must also be 1536
const queryEmbedding = await generateEmbedding(text);
console.log(queryEmbedding.length); // Should be 1536

“Inner product not supported” (SQLite)

Section titled ““Inner product not supported” (SQLite)”

Cause: sqlite-vec doesn’t support inner product metric.

Solution: Use cosine or L2:

// Instead of:
d.embedding.similarTo(query, 10, { metric: "inner_product" })
// Use:
d.embedding.similarTo(query, 10, { metric: "cosine" })

”Property ‘x’ does not exist on type”

Section titled “”Property ‘x’ does not exist on type””

Cause: Accessing a property not defined in your schema.

Solution: Ensure the property is in your Zod schema:

const Person = defineNode("Person", {
schema: z.object({
name: z.string(),
email: z.string().optional(),
}),
});
// Now both properties are available with correct types
const person = await store.nodes.Person.getById(id);
person?.name; // string
person?.email; // string | undefined

Cause: Complex generic inference limitations.

Solution: Use explicit typing or simplify:

// If inference fails, be explicit
.select((ctx) => ({
name: ctx.p.name as string,
company: ctx.c.name as string,
}))
  1. Check the Limitations page for known constraints
  2. Review Architecture to understand how TypeGraph works
  3. Search GitHub Issues for similar problems
  4. Open a new issue with a minimal reproduction case