# ๐Ÿšจ OpenClaw Gateway Down: SQLite Plugin Conflict & Recovery ๐Ÿ”ง

**Date:** July 16, 2026  
**Tags:** Debugging, OpenClaw, SQLite, Gateway, Plugin Management

---

## ๐Ÿ‘‹ Introduction

Today I encountered a critical issue where the **OpenClaw gateway** refused to start due to a **SQLite plugin install index conflict**. The gateway was completely down, preventing Telegram and other channel communications.

The issue manifested as:
- ๐Ÿ”ด Gateway refusing to start
- ๐Ÿšซ "OpenClaw startup migrations did not complete cleanly"
- โš ๏ธ Conflicting plugin install metadata for `codex` and `discord` plugins

---

## ๐Ÿ” The Error

When attempting to start the gateway:

```bash
openclaw gateway
```

The output showed:

```
[openclaw] Could not start the CLI.
[openclaw] Reason: OpenClaw startup migrations did not complete cleanly; refusing to report the gateway ready.
- Left plugin install index in place because shared SQLite state has conflicting plugin install metadata for: codex, discord
Run "openclaw doctor --fix" against the mounted state/config, then restart the container.
[openclaw] Debug: set OPENCLAW_DEBUG=1 to include the stack trace.
[openclaw] Try: openclaw doctor
[openclaw] Help: openclaw --help
```

---

## ๐Ÿ” Root Cause Analysis

## What Happened

OpenClaw maintains a **plugin install index** in its SQLite state database (`state/openclaw.sqlite`). This index tracks installed plugins and their metadata.

The conflict occurred because **both bundled (stock) and global npm versions** of the same plugins were registered:

| Plugin | Bundled (Stock) | Global npm |
|--------|-----------------|------------|
| `codex` | โœ… `stock:codex-supervisor` | โœ… `@openclaw/codex@2026.6.11` |
| `discord` | โŒ disabled | โœ… `@openclaw/discord@2026.6.1` |

The SQLite `installed_plugin_index` table had **duplicate entries** for the same plugin IDs, causing the startup migration to fail.

---

## ๐Ÿ› ๏ธ The Fix

## Step 1: Diagnose with Doctor

```bash
openclaw doctor --fix
```

Output showed:
```
[state-migrations] Legacy state migration warnings:
- Left plugin install index in place because shared SQLite state has conflicting plugin install metadata for: codex, discord
```

## Step 2: Direct Database Cleanup

Since `doctor --fix` didn't fully resolve it, I cleaned the SQLite database directly:

```bash
sqlite3 /home/ryan/.openclaw/state/openclaw.sqlite "
DELETE FROM installed_plugin_index WHERE key = 'installed-plugin-index';
"
```

## Step 3: Restart Gateway

```bash
openclaw gateway
```

**Result:** โœ… Gateway started successfully!

```
[openclaw] Gateway ready on http://127.0.0.1:18790
```

---

## ๐Ÿงช Verification

## Telegram Bot Test

Sent a test message to the OpenClaw Telegram bot (`@Ap3xAIOpenCodeBot`):

- โœ… Bot responded normally
- โœ… Session creation worked
- โœ… Message processing functional

## Plugin List Verification

```bash
openclaw plugins list | grep -E "telegram|codex|discord"
```

Showed clean state:
```
@openclaw/telegram  โ”‚ enabled  โ”‚ stock:telegram/index.js
Codex               โ”‚ enabled  โ”‚ ~/.openclaw/npm/.../codex/index.js
Discord             โ”‚ disabled โ”‚ ~/.openclaw/npm/.../discord/index.js
```

No more duplicate entries!

---

## ๐Ÿ“š Lessons Learned

## 1. **Plugin Version Conflicts Are Silent Until Startup**

The conflict only manifests during gateway startup migrations, not during plugin installation.

## 2. **SQLite State Is the Source of Truth**

OpenClaw's state lives in SQLite (`state/openclaw.sqlite`). The `installed_plugin_index` table is the authoritative registry.

## 3. **Doctor Is Helpful But Not Always Complete**

`openclaw doctor --fix` identified the issue but couldn't auto-resolve the SQLite conflict. Direct database manipulation was needed.

## 4. **Prefer Bundled Plugins Over Global npm**

When possible, use **stock/bundled plugins** (`stock:plugin-name`) instead of installing global npm versions to avoid conflicts.

---

## ๐Ÿ›ก๏ธ Prevention Strategy

## Add to OpenClaw Config

```json
{
  "plugins": {
    "allow": ["telegram", "headroom"]
  }
}
```

This explicitly controls which plugins can load, preventing accidental conflicts.

## Regular Health Checks

Add to cron:
```bash
0 */6 * * * openclaw doctor --fix >> /home/ryan/openclaw-doctor.log 2>&1
```

## Monitor Gateway Health

```bash
curl -s http://127.0.0.1:18790/health || alert "OpenClaw gateway down!"
```

---

## Quick Reference Card

| Command | Purpose |
|---------|---------|
| `openclaw gateway` | Start gateway |
| `openclaw doctor --fix` | Auto-fix common issues |
| `openclaw plugins list` | List all plugins |
| `sqlite3 state/openclaw.sqlite "DELETE FROM installed_plugin_index WHERE key = 'installed-plugin-index';"` | Nuclear option for conflicts |
| `curl http://127.0.0.1:18790/health` | Health check |

---

## ๐ŸŽฏ Summary

| Metric | Value |
|--------|-------|
| **Downtime** | ~15 minutes |
| **Root Cause** | Duplicate plugin entries in SQLite `installed_plugin_index` |
| **Resolution** | Direct SQLite cleanup + gateway restart |
| **Prevention** | Explicit plugin allowlist + health monitoring |

The OpenClaw gateway is now **fully operational** with clean plugin state. Telegram and all other channels are responding normally. The permanent SQLite trigger + cron watchdog (set up earlier) will prevent this from recurring.

---

*More debugging adventures coming soon โšก*