> ## Documentation Index
> Fetch the complete documentation index at: https://sonamu.cartanova.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting

> HMR troubleshooting guide

export const FileItem = ({name, description, children}) => {
  const isLeaf = !children;
  const ext = getFileExtension(name);
  const extStyle = ext ? getExtensionStyle(ext) : null;
  return <div style={{
    marginLeft: "30px"
  }}>
      <div style={{
    display: "flex",
    alignItems: "center",
    gap: "4px"
  }}>
        <span style={{
    position: "relative",
    display: "inline-block"
  }}>
          <span className="file-icon">{isLeaf && !name.endsWith("/") ? "📄" : "📁"}</span>
          {ext && <span style={{
    position: "absolute",
    bottom: "2px",
    right: "0px",
    fontSize: "5px",
    fontWeight: "bold",
    padding: "1px",
    borderRadius: "2px",
    lineHeight: "1",
    minWidth: "8px",
    textAlign: "center",
    ...extStyle
  }}>
              {ext}
            </span>}
        </span>
        <code>{name}</code>
        {description && <span className="description"> - {description}</span>}
      </div>
      {children}
    </div>;
};

export const FileTree = ({children}) => {
  return <div className="file-tree" style={{
    margin: "20px",
    marginLeft: "-30px"
  }}>
      {children}
    </div>;
};

Problems that may occur during HMR usage and practical solutions.

## Changes Not Reflected

### Situation

```typescript theme={null}
// Modified user.model.ts
export class UserModel extends BaseModelClass {
  isActive(): boolean {
    return this.status === "active"; // Added this logic but...
  }
}
```

Saved but still getting `isActive is not a function` error on API call.

### Cause 1: Using Static Import

There's likely a static import of UserModel somewhere.

**How to check:**

```bash theme={null}
# Find static imports in project
grep -r "import.*UserModel.*from" src/

# Example output:
# src/some-file.ts:import { UserModel } from "./user.model";  ← 🚨 This is the problem!
```

**Solution: Change to dynamic import**

```typescript theme={null}
// Before - ❌
import { UserModel } from "./application/user/user.model";

app.get("/users", async (req, res) => {
  const users = await UserModel.findMany();
  res.json(users);
});

// After - ✅
app.get("/users", async (req, res) => {
  const { UserModel } = await import("./application/user/user.model");
  const users = await UserModel.findMany();
  res.json(users);
});
```

<Note>
  Sonamu's Syncer automatically handles dynamic imports for Entity-based files, so this problem
  doesn't occur in typical Model/API files. It mainly occurs in custom scripts or initialization
  code.
</Note>

### Cause 2: Error Hidden in Console

An error may have occurred during HMR but you missed it.

**How to check:**

Scroll through the terminal to check for errors like:

```bash theme={null}
🔄 Invalidated:
- src/user/user.model.ts

❌ Error loading module: /path/to/user.model.ts
SyntaxError: Unexpected token '}'
    at Module._compile (internal/modules/cjs/loader.js:1137:14)
```

**Solution:**

Check the file and line number in the error message and fix it.

### Cause 3: Cache Corruption

Rarely, ESM cache may not be completely removed.

**Solution: Server restart**

```bash theme={null}
# After stopping with Ctrl+C
pnpm dev
```

## "File not imported dynamically" Error

### Situation

```
FileNotImportedDynamicallyException: File /path/to/user.model.ts must be imported dynamically
```

### Cause

A Boundary file (user.model.ts) was loaded via static import somewhere.

### Quick Fix

**Option 1: Change static import to dynamic import (Recommended)**

Find the file mentioned in the error message:

```typescript theme={null}
// Before
import { UserModel } from "./user.model";

// After
const { UserModel } = await import("./user.model");
```

**Option 2: Exclude the file from Boundary**

If you really can't change to dynamic import:

```typescript theme={null}
// hmr-hook-register.ts
await hot.init({
  rootDirectory: process.env.API_ROOT_PATH,
  boundaries: [
    `./src/**/*.ts`,
    `!./src/config/**/*`, // Exclude config folder
  ],
});
```

**Option 3: Ignore the error (Not recommended)**

```typescript theme={null}
await hot.init({
  boundaries: [`./src/**/*.ts`],
  throwWhenBoundariesAreNotDynamicallyImported: false, // Ignore error
});
```

<Warning>
  Using Option 3 means HMR won't work for that file. Not recommended as it significantly reduces
  development convenience.
</Warning>

## Memory Increase on Reload

### Situation

```bash theme={null}
# Initially
RSS: 150MB, Heap: 80MB

# After modifying files 10 times
RSS: 350MB, Heap: 200MB  # 🚨 Memory keeps increasing!
```

### Cause

Resources from previous modules (timers, event listeners, connections, etc.) aren't cleaned up, causing leaks.

**How to check:**

```typescript theme={null}
// Runs on each reload
console.log("Active handles:", process._getActiveHandles().length);
console.log("Active requests:", process._getActiveRequests().length);

// If numbers keep increasing, resource leak is occurring!
```

### Solution

Clean up resources with `import.meta.hot.dispose()`:

**Example 1: Timers**

```typescript theme={null}
// notification-polling.ts
const timer = setInterval(async () => {
  await checkNewNotifications();
}, 5000);

// ✅ Clean up timer before reload
import.meta.hot?.dispose(() => {
  clearInterval(timer);
  console.log("✨ Timer cleaned up");
});
```

**Example 2: WebSocket**

```typescript theme={null}
// websocket-client.ts
const ws = new WebSocket("ws://notification-server.com");

ws.on("message", (data) => {
  console.log("Notification:", data);
});

// ✅ Close connection before reload
import.meta.hot?.dispose(() => {
  ws.close();
  console.log("✨ WebSocket closed");
});
```

**Example 3: Event Listeners**

```typescript theme={null}
// event-handler.ts
import { EventEmitter } from "events";

const emitter = new EventEmitter();

function handleData(data: any) {
  console.log("Data received:", data);
}

emitter.on("data", handleData);

// ✅ Remove listener before reload
import.meta.hot?.dispose(() => {
  emitter.removeListener("data", handleData);
  console.log("✨ Event listener removed");
});
```

**Example 4: Database Connection Pool**

```typescript theme={null}
// custom-db-pool.ts
import { Pool } from "pg";

const pool = new Pool({
  host: "localhost",
  port: 5432,
  database: "mydb",
});

// ✅ Close pool before reload
import.meta.hot?.dispose(async () => {
  await pool.end();
  console.log("✨ DB pool closed");
});
```

## API Registered Multiple Times

### Situation

```bash theme={null}
⚠️ Warning: Route POST /api/user/create is already registered
⚠️ Warning: Route GET /api/user/list is already registered
```

Server log shows warnings about the same API being registered multiple times.

### Cause

Existing APIs weren't removed when Model file was reloaded.

### Check

Check if API removal is shown in Syncer logs:

```bash theme={null}
🔄 Invalidated:
- src/user/user.model.ts (with 8 APIs)  # ← API count should be shown

# If "with X APIs" is missing, they weren't removed!
```

### Solution

Syncer normally handles this automatically, but if problem persists:

**1. Server restart**

```bash theme={null}
# Simplest solution
Ctrl+C
pnpm dev
```

**2. Check Syncer logic (rare cases)**

```typescript theme={null}
// Check syncer.ts
removeInvalidatedRegisteredApis(invalidatedPath: AbsolutePath) {
  if (!invalidatedPath.endsWith(".model.ts")) {
    return [];
  }

  const entityId = EntityManager.getEntityIdFromPath(invalidatedPath);
  const toRemove = registeredApis.filter(
    api => api.modelName === `${entityId}Model`
  );

  for (const api of toRemove) {
    registeredApis.splice(registeredApis.indexOf(api), 1);
  }

  return toRemove;
}
```

If this logic isn't executing, it may be a Sonamu bug. Please report to GitHub Issues.

## Circular Dependency Issues

### Situation

```bash theme={null}
# When modifying a file
🔄 Invalidated:
- src/user/user.model.ts
- src/post/post.model.ts
- src/user/user.model.ts  # ← 🚨 Appears again!
- src/post/post.model.ts  # ← 🚨 Infinite loop!

# Or
RangeError: Maximum call stack size exceeded
```

HMR gets stuck in infinite loop or some modules don't load.

### Cause

Circular reference between Models:

```typescript theme={null}
// user.model.ts
import { PostModel } from "../post/post.model";

export class UserModel extends BaseModelClass {
  async getPosts() {
    return PostModel.findMany({ where: { userId: this.id } });
  }
}

// post.model.ts
import { UserModel } from "../user/user.model"; // ← 🚨 Circular reference!

export class PostModel extends BaseModelClass {
  async getAuthor() {
    return UserModel.findById(this.userId);
  }
}
```

### Solutions

**Option 1: Import only types (Recommended)**

```typescript theme={null}
// user.model.ts
import type { PostSaved } from "../post/post.types"; // ✅ Types only

export class UserModel extends BaseModelClass {
  async getPosts(): Promise<PostSaved[]> {
    // Load actual class via dynamic import
    const { PostModel } = await import("../post/post.model");
    return PostModel.findMany({ where: { userId: this.id } });
  }
}

// post.model.ts
import type { UserSaved } from "../user/user.types"; // ✅ Types only

export class PostModel extends BaseModelClass {
  async getAuthor(): Promise<UserSaved> {
    const { UserModel } = await import("../user/user.model");
    return UserModel.findById(this.userId);
  }
}
```

**Option 2: Separate common types file**

```typescript theme={null}
// shared-types.ts
export type UserSaved = {
  /* ... */
};
export type PostSaved = {
  /* ... */
};

// user.model.ts
import type { PostSaved } from "./shared-types";

// post.model.ts
import type { UserSaved } from "./shared-types";
```

**Option 3: Redesign dependency direction**

```typescript theme={null}
// Reference user.model.ts only from post.model.ts
import { UserModel } from "../user/user.model"; // ✅ Unidirectional

export class PostModel extends BaseModelClass {
  async getAuthor() {
    return UserModel.findById(this.userId);
  }
}

// Don't reference post.model.ts from user.model.ts
// (Handle in PostApi if needed)
```

## HMR Not Working for Specific Files

### Situation

```typescript theme={null}
// user.model.ts modification → ✅ HMR works
// post.model.ts modification → ✅ HMR works
// admin-helper.ts modification → ❌ Not reflected
```

### Cause 1: Not Matching Boundary Pattern

**Check:**

```typescript theme={null}
const dump = await hot.dump();
const helper = dump.find((d) => d.nodePath.includes("admin-helper.ts"));

if (!helper) {
  console.log("❌ This file is not a Boundary!");
}
```

**Fix:**

```typescript theme={null}
// hmr-hook-register.ts
await hot.init({
  rootDirectory: process.env.API_ROOT_PATH,
  boundaries: [
    `./src/**/*.ts`, // Should already be included
  ],
});
```

### Cause 2: File Not Imported

HMR only tracks **files that are actually imported**.

**Check:**

```typescript theme={null}
const dump = await hot.dump();
console.log(`Total tracked files: ${dump.length}`);

// If admin-helper.ts isn't in the list, nothing is importing it!
```

**Fix:**

Import the file somewhere, or delete it if not needed.

## SSR File Changes Not Reloading

### Situation

```typescript theme={null}
// Modify src/ssr/routes.ts
// Save but not reflected
```

### Cause

SSR files are handled specially.

### Fix

Syncer automatically handles SSR file changes, but if manual reload is needed:

```bash theme={null}
# Server restart
Ctrl+C
pnpm dev
```

Or in code:

```typescript theme={null}
// Check SSR file handling in syncer.ts
if (diffFilePath.includes("/src/ssr/")) {
  console.log("SSR config changed - reloading...");
  await hot.invalidateFile(diffFilePath, event);
  await this.autoloadSSRRoutes();
}
```

## HMR Too Slow

### Situation

```bash theme={null}
# Save file
# 5 seconds later...
🔄 Invalidated:  # ← 🚨 Too slow!
```

### Cause

Dependency tree is too deep or wide, invalidating many files.

**Check:**

```typescript theme={null}
const dump = await hot.dump();
const userModel = dump.find((d) => d.nodePath.includes("user.model.ts"));

console.log(`Dependencies: ${userModel?.children?.length}`);
// If over 100, that's a problem!
```

### Solutions

**1. Minimize imports**

```typescript theme={null}
// ❌ Bad example - import all Models
import { UserModel } from "./user.model";
import { PostModel } from "./post.model";
import { CommentModel } from "./comment.model";
import { CategoryModel } from "./category.model";
import { TagModel } from "./tag.model";
// ... 20 more

// ✅ Good example - only what's needed
import { UserModel } from "./user.model";
import { PostModel } from "./post.model";
```

**2. Optimize library imports like lodash**

```typescript theme={null}
// ❌ Bad example
import * as lodash from "lodash";

// ✅ Good example
import { pick, omit } from "lodash";
```

**3. Reduce Boundary scope**

```typescript theme={null}
// hmr-hook-register.ts
await hot.init({
  rootDirectory: process.env.API_ROOT_PATH,
  boundaries: [
    // Only frequently changed files instead of all
    `./src/**/*.model.ts`,
    `./src/**/*.api.ts`,
  ],
});
```

## Debugging Tips

### Enable HMR Logs

To see detailed HMR operation:

```bash theme={null}
DEBUG=hmr-hook:* pnpm dev
```

Output example:

```bash theme={null}
hmr-hook:loader File change src/user/user.model.ts
hmr-hook:dependency_tree Invalidating /path/to/user.model.ts
hmr-hook:dependency_tree Finding dependents...
hmr-hook:dependency_tree Found 3 dependent files
hmr-hook:loader Invalidated 3 files
```

### Check Dependency Tree

```typescript theme={null}
const dump = await hot.dump();

// Check dependencies for specific file
const userModel = dump.find((d) => d.nodePath.includes("user.model.ts"));
console.log("Children:", userModel?.children);

// Save entire tree as JSON
import { writeFileSync } from "fs";
writeFileSync("dependency-tree.json", JSON.stringify(dump, null, 2));
```

### Track Invalidated Files

Pay close attention to logs Syncer prints to console:

```bash theme={null}
🔄 Invalidated:
- src/user/user.model.ts (with 8 APIs)
- src/user/user.api.ts
- src/post/post.api.ts  # ← Why post.api.ts too?

# user.model.ts changed but post.api.ts also reloaded
# → post.api.ts uses UserModel
```

### Monitor Memory Usage

```typescript theme={null}
// memory-monitor.ts
setInterval(() => {
  const used = process.memoryUsage();
  const timestamp = new Date().toISOString();

  console.log(`[${timestamp}] Memory:`, {
    rss: `${Math.round(used.rss / 1024 / 1024)}MB`,
    heapUsed: `${Math.round(used.heapUsed / 1024 / 1024)}MB`,
    heapTotal: `${Math.round(used.heapTotal / 1024 / 1024)}MB`,
    external: `${Math.round(used.external / 1024 / 1024)}MB`,
  });
}, 10000); // Every 10 seconds
```

## Last Resort: Full Restart

When all solutions fail:

```bash theme={null}
# 1. Stop process
Ctrl+C

# 2. Delete build directory
rm -rf dist/

# 3. Delete checksums
rm -rf .sonamu/checksums/

# 4. Delete node_modules (for really serious cases)
rm -rf node_modules/
pnpm install

# 5. Restart
pnpm dev
```

## Getting Help

If the problem still isn't resolved:

### 1. Report to GitHub Issues

Create a new issue at:

[https://github.com/cartanova-ai/sonamu/issues](https://github.com/cartanova-ai/sonamu/issues)

### 2. Include the Following Information

Please provide this information for problem resolution:

* Sonamu version (`package.json`)
* Node.js version (`node -v`)
* Error message that occurred
* Minimal reproducible example
* HMR logs (`DEBUG=hmr-hook:* pnpm dev`)

### 3. Include File Structure Example

Clearly show the file structure where the problem occurs:

<Card>
  <FileTree>
    <FileItem name="src/">
      <FileItem name="user/">
        <FileItem name="user.model.ts" description="When modifying this file" />

        <FileItem name="user.api.ts" description="HMR doesn't work" />
      </FileItem>

      <FileItem name="post/">
        <FileItem name="post.model.ts" />
      </FileItem>
    </FileItem>
  </FileTree>
</Card>

**Please include an example description:**

```
Symptoms:
- Modify and save user.model.ts
- Console shows "Invalidated: user.model.ts"
- But user.api.ts still executes old code
- Server restart fixes it

Attempted solutions:
1. Check dynamic import → Already dynamically loaded
2. Server restart → Temporarily fixed but recurs
3. Cache deletion (rm -rf dist/) → No effect

HMR logs:
[Attach log content]
```

Detailed descriptions like this help you get faster responses!
