# How to Troubleshoot Common Development Issues in OpenWork

> Troubleshoot common OpenWork development issues by checking port conflicts, isolating stale profiles, and verifying backend ports. Resolve errors efficiently with these steps.

- Repository: [Different AI/openwork](https://github.com/different-ai/openwork)
- Tags: how-to-guide
- Published: 2026-08-14

---

**Most OpenWork development errors can be resolved by checking the dev banner for profile and CDP port conflicts, isolating stale profiles with `OPENWORK_DEV_PROFILE=auto`, and verifying that the Vite and Den backend ports are reachable.**

OpenWork is a multi-process desktop application that combines an Electron UI, a Vite-powered web server, and an optional OpenWork Den backend. When you run `pnpm dev`, failures typically surface in one of these interconnected layers. Knowing how to troubleshoot common development issues in OpenWork will help you pinpoint and fix errors quickly across the entire stack.

## Understanding the OpenWork Development Stack

OpenWork runs three core processes during development. Problems usually map to the Electron launcher, the Vite dev-server, or the Den backend, with additional friction from macOS keychain behavior and workspace profile state.

- **Electron launch layer** – Profile lock contention, missing Chrome DevTools Protocol (CDP) ports, or mock keychain mismatches can cause `pnpm dev` to exit silently or hang. According to the source code in [`dev/README.md`](https://github.com/different-ai/openwork/blob/main/dev/README.md), the dev profile mechanics are described at lines 86-94.
- **Vite dev-server layer** – Port conflicts, stale `VITE_DEN_API_BASE_URL` values, or missing environment variables produce "Port already in use" errors, 404 API responses, and CORS failures. The headless-web description in [`dev/README.md`](https://github.com/different-ai/openwork/blob/main/dev/README.md) (lines 107-113) documents these variables.
- **Den backend layer** – If MySQL is not started, the proxy target is mis-configured, or `DEN_MYSQL_URL` is missing, the Den API returns 500 errors and migration scripts abort. The Docker-based Den dev commands are documented in [`packaging/docker/README.md`](https://github.com/different-ai/openwork/blob/main/packaging/docker/README.md) at lines 16-33.
- **Keychain and credentials layer** – On macOS, using the real keychain in a fresh profile can trigger a modal that blocks Electron and makes the app appear frozen. The mock-keychain flag is defined in [`dev/README.md`](https://github.com/different-ai/openwork/blob/main/dev/README.md) at lines 94-100.
- **Workspace configuration layer** – When `OPENWORK_DEV_PROFILE` points to a stale directory or the workspace JSON is out of sync, files fail to persist and the runtime throws "cannot read ~/.config/openwork" errors.

## Step-by-Step Debugging Workflow

Follow this exact sequence to isolate and resolve the majority of OpenWork development issues. Each step targets a specific layer so you can identify the root cause without changing multiple variables at once.

### 1. Read the Dev Banner

After running `pnpm dev`, inspect the console banner for the profile path and CDP URL (for example, `dev profile=… cdp=http://127.0.0.1:9223`). Verify that the profile path exists and that the CDP URL is reachable. If the banner does not appear, Electron likely failed before the web server started.

### 2. Validate Ports

Ensure the CDP port (default **9223**) and the Vite port (default **5178**) are free. If either is already bound, set `OPENWORK_ELECTRON_REMOTE_DEBUG_PORT=0` or `OPENWORK_WEB_PORT=0` before re-running `pnpm dev` to let the system assign an ephemeral port.

### 3. Inspect Logs

Electron runtime logs are written to `.openwork-run/electron.log`. Vite logs stream in the terminal where you launched the process. Search for "profile lock" or "cannot bind" messages that explain silent exits.

### 4. Isolate the Profile

Run `pnpm dev:worktree` to auto-generate a fresh profile by setting `OPENWORK_DEV_PROFILE=auto`. This avoids stale credential caches and broken workspace JSON states that are cached in old directories.

### 5. Toggle Keychain Mode

If a macOS keychain password modal appears and freezes the app, start the dev server with `OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1 pnpm dev`. Set this flag to `0` only when you explicitly need to test against the real macOS keychain.

### 6. Verify Den Connectivity

For headless-web or local Den setups, set `OPENWORK_DEV_DEN_PROXY_TARGET=http://127.0.0.1:3005` (or the port matching your local Den instance). Confirm the Den API is healthy with `curl http://127.0.0.1:8788/api/den/openapi.json`.

### 7. Clean Up Stray Processes

Stray Electron processes often retain the CDP port after a crash. Terminate them with `pkill -f electron` and then re-run `pnpm dev`.

## Common OpenWork Development Issues and Fixes

### Fixing Electron Profile Lock and Silent Exits

Profile lock contention is one of the most common reasons `pnpm dev` hangs. As implemented in `different-ai/openwork`, the dev profile description in [`dev/README.md`](https://github.com/different-ai/openwork/blob/main/dev/README.md) (lines 86-94) explains how the runtime resolves `OPENWORK_DEV_PROFILE`. When two instances reference the same profile directory, Chromium locks the user-data folder and Electron cannot launch.

To bypass this, use an isolated profile:

```bash
OPENWORK_DEV_PROFILE=auto \
OPENWORK_ELECTRON_REMOTE_DEBUG_PORT=0 \
pnpm dev

```

Alternatively, run the worktree-specific helper:

```bash
pnpm dev:worktree

```

### Resolving Vite Port Conflicts and CORS Errors

Stale `VITE_DEN_API_BASE_URL` values or hard-coded ports cause the Vite layer to return 404s for `/api/den` requests. The headless-web flow in [`dev/README.md`](https://github.com/different-ai/openwork/blob/main/dev/README.md) (lines 107-113) shows that the web server relies on environment variables to locate the Den backend. Force dynamic port selection and set a valid Den proxy target:

```bash
OPENWORK_WEB_PORT=0 \
OPENWORK_DEV_DEN_PROXY_TARGET=http://127.0.0.1:3005 \
pnpm dev:web-local

```

For a detached headless web UI—useful for automation agents—run:

```bash
pnpm dev:headless-web --detach

```

This command is referenced in [`dev/AGENTS.md`](https://github.com/different-ai/openwork/blob/main/dev/AGENTS.md) and keeps the Vite server alive without an attached terminal.

### Diagnosing Den Backend and MySQL Failures

When the Den API fails with 500 errors or migrations abort, the issue is usually a missing `DEN_MYSQL_URL` or a mis-configured proxy target. The Docker-based Den commands in [`packaging/docker/README.md`](https://github.com/different-ai/openwork/blob/main/packaging/docker/README.md) (lines 16-33) cover local MySQL and Den container startup. First, confirm the Den service is reachable:

```bash
curl -s http://127.0.0.1:8788/api/den/openapi.json | jq .

```

If this returns valid JSON, the backend is healthy and the problem likely lives in the Vite-to-Den proxy configuration. If it fails, check that your MySQL container is running and that `DEN_MYSQL_URL` is exported in the environment.

### Handling macOS Keychain Modals in Development

On a fresh dev profile, Electron may attempt to use the real macOS keychain, triggering a blocking password dialog. The mock-keychain flag documented in [`dev/README.md`](https://github.com/different-ai/openwork/blob/main/dev/README.md) (lines 94-100) prevents this.

Launch with the mock keychain enabled:

```bash
OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1 pnpm dev

```

Only disable this flag (`=0`) when you are explicitly testing credential storage against the real macOS keychain.

## Diagnostic Commands and Log Inspection

Before changing environment variables, gather evidence from the running system. These commands read the Electron log, verify port availability, and test the Den API directly.

Check the Electron log for profile lock messages:

```bash
cat .openwork-run/electron.log | grep "profile lock"

```

Verify port availability:

```bash
lsof -i :9223
lsof -i :5178

```

Query the Den OpenAPI endpoint:

```bash
curl -s http://127.0.0.1:8788/api/den/openapi.json | jq .

```

Kill all lingering Electron processes:

```bash
pkill -f electron

```

## Key Source Files for Deep Debugging

The `different-ai/openwork` repository contains several authoritative files that define startup behavior. Refer to the following paths when you need to trace the exact implementation of profile handling, port assignment, and backend proxy logic.

- **[`dev/README.md`](https://github.com/different-ai/openwork/blob/main/dev/README.md)** – Overview of dev commands, profile handling (`OPENWORK_DEV_PROFILE`), and headless-web flow (lines 86-113). This is the central source for startup flags and profile mechanics.
- **[`dev/HANDOFF.md`](https://github.com/different-ai/openwork/blob/main/dev/HANDOFF.md)** – Detailed instructions for Den services, MySQL setup, and profile locking. It explains how the Den backend and MySQL interact with the dev profile.
- **[`dev/.opencode/skills/browser-automation/SKILL.md`](https://github.com/different-ai/openwork/blob/main/dev/.opencode/skills/browser-automation/SKILL.md)** – Notes on CDP port overrides and Electron launch variations used by automation scripts.
- **[`packaging/docker/README.md`](https://github.com/different-ai/openwork/blob/main/packaging/docker/README.md)** – Docker-based Den dev environment and seed scripts. Consult this when local MySQL or Den containers fail to start (lines 16-33).
- **[`dev/AGENTS.md`](https://github.com/different-ai/openwork/blob/main/dev/AGENTS.md)** – Launch command reference for detached headless web (`pnpm dev:headless-web --detach`) used by automation agents.

## Summary

- **Check the dev banner** after `pnpm dev` to confirm the active profile path and CDP URL are valid.
- **Free conflicting ports** by setting `OPENWORK_ELECTRON_REMOTE_DEBUG_PORT=0` or `OPENWORK_WEB_PORT=0` before startup.
- **Use a fresh profile** with `OPENWORK_DEV_PROFILE=auto` or `pnpm dev:worktree` to eliminate stale credential caches.
- **Enable the mock keychain** with `OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1` when macOS modals block Electron.
- **Validate Den connectivity** by curling `http://127.0.0.1:8788/api/den/openapi.json` and confirming the proxy target in `OPENWORK_DEV_DEN_PROXY_TARGET`.
- **Read `.openwork-run/electron.log`** and the terminal output for exact error strings like "profile lock" or "cannot bind".

## Frequently Asked Questions

### Why does `pnpm dev` exit silently without opening a window?

Silent exits usually indicate an Electron profile lock or a CDP port conflict. Check `.openwork-run/electron.log` for "profile lock" messages and verify that port 9223 is free. If another Electron instance is running, terminate it with `pkill -f electron` and restart.

### How do I run OpenWork without triggering the macOS keychain password dialog?

Set the mock-keychain environment variable before launching: `OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1 pnpm dev`. This flag is documented in [`dev/README.md`](https://github.com/different-ai/openwork/blob/main/dev/README.md) (lines 94-100) and prevents the real macOS keychain from blocking the app on a fresh profile. Only set it to `0` when you explicitly need to test real credential storage.

### What should I do when the Den API returns 500 errors?

First confirm the Den container or local process is alive by running `curl http://127.0.0.1:8788/api/den/openapi.json`. If that fails, check that MySQL is running and that `DEN_MYSQL_URL` is set. If the Den service is healthy, verify `OPENWORK_DEV_DEN_PROXY_TARGET` points to the correct port in your Vite environment.

### How can I run the web UI without the Electron shell?

Use the headless-web command: `pnpm dev:headless-web --detach`. This is documented in [`dev/AGENTS.md`](https://github.com/different-ai/openwork/blob/main/dev/AGENTS.md) and starts the Vite server without the Electron UI. It is especially useful for browser automation agents and lightweight local testing.