Open Harness
Learn

Troubleshooting

Common errors and how to fix them

Troubleshooting

Common errors and their solutions.

Installation Errors

Cannot find module '@open-harness/core'

Error: Cannot find module '@open-harness/core'

Cause: Dependencies not installed.

Fix: Run the install command:

bun install

Cannot find module '@open-harness/vitest'

Error: Cannot find module '@open-harness/vitest'

Cause: Vitest plugin not installed.

Fix: Install the Vitest plugin:

bun add -D @open-harness/vitest vitest

Configuration Errors

State type mismatch

Type 'string' is not assignable to type 'null'

Cause: Initial state doesn't match the TState type parameter.

Fix: Ensure your state matches your type definition:

// Define your state type
type State = { input: string; result: string | null };

// Create workflow with correct type
const { agent, runReactive } = createWorkflow<State>();

// Initial state must match
const result = await runReactive({
  agents: { myAgent },
  state: { input: "Hello", result: null }, // ✓ Correct
  harness: new ClaudeHarness(),
});

Invalid activateOn pattern

Error: Invalid signal pattern: "invalid"

Cause: Signal pattern doesn't match expected format.

Fix: Use valid signal patterns:

// Valid patterns
activateOn: ["workflow:start"]
activateOn: ["agent:completed"]
activateOn: ["analysis:complete"]  // Custom signal
activateOn: ["state:result:changed"]

No harness configured

Error: No harness configured for agent

Cause: Missing harness in runReactive config.

Fix: Pass a harness:

import { createWorkflow, ClaudeHarness } from "@open-harness/core";

const result = await runReactive({
  agents: { myAgent },
  state: initialState,
  harness: new ClaudeHarness(), // Required
});

Runtime Errors

Workflow never terminates

Cause: endWhen condition never returns true and signals stop flowing.

Fix: Check your termination condition:

const result = await runReactive({
  agents: { analyzer },
  state: { input: "Hello", result: null },
  harness,
  // Ensure this becomes true
  endWhen: (state) => state.result !== null,
});

Or add a timeout:

const result = await runReactive({
  agents: { analyzer },
  state: initialState,
  harness,
  timeout: 30000, // 30 second safety net
});

Agent not activating

Cause: The activateOn signal was never emitted, or when guard returned false.

Fix: Check your signal chain:

// Agent waits for analysis:complete
const reviewer = agent({
  prompt: "Review the analysis",
  activateOn: ["analysis:complete"],
});

// But analyzer doesn't emit it!
const analyzer = agent({
  prompt: "Analyze input",
  activateOn: ["workflow:start"],
  // Missing: emits: ["analysis:complete"]
});

Add the emits declaration:

const analyzer = agent({
  prompt: "Analyze input",
  activateOn: ["workflow:start"],
  emits: ["analysis:complete"], // Now reviewer will activate
});

State not updating

Cause: Agent doesn't have updates field.

Fix: Specify which state key to update:

const analyzer = agent({
  prompt: "Analyze: {{ state.input }}",
  activateOn: ["workflow:start"],
  updates: "result", // Agent output goes to state.result
});

Agent guard always false

// This agent never runs
const reviewer = agent({
  prompt: "Review",
  activateOn: ["analysis:complete"],
  when: (state) => state.needsReview === true,
});

Cause: when guard condition never met.

Fix: Ensure state has the expected shape:

// Make sure needsReview can become true
type State = {
  analysis: string | null;
  needsReview: boolean;
};

Harness Errors

Authentication failed

Error: Claude API authentication failed

Cause: Running outside Claude Code environment.

Fix: Open Harness uses Claude Code subscription authentication. Run your code from within Claude Code:

# From Claude Code terminal
bun run agent.ts

Authentication

Open Harness uses your Claude Code subscription for authentication. No API key is required when running from Claude Code.

Rate limit exceeded

Error: Rate limit exceeded

Cause: Too many requests in a short period.

Fix: The error signal includes retry information:

const errors = result.signals.filter(s => s.name === "harness:error");
for (const error of errors) {
  if (error.payload.retryAfter) {
    console.log(`Retry after ${error.payload.retryAfter} seconds`);
  }
}

Harness error in signal trace

const result = await runReactive({ /* ... */ });

const errors = result.signals.filter(s => s.name === "harness:error");
if (errors.length > 0) {
  console.error("Harness errors:", errors);
}

Test Errors

Matcher not recognized

TypeError: expect(...).toContainSignal is not a function

Cause: Vitest matchers not registered.

Fix: Add the setup file to your Vitest config:

vitest.config.ts
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    setupFiles: ["@open-harness/vitest/setup"],
  },
});

Or manually register in your test:

import { expect } from "vitest";
import { toContainSignal, toHaveSignalsInOrder } from "@open-harness/vitest";

expect.extend({ toContainSignal, toHaveSignalsInOrder });

Test timeout

Error: Test timed out after 5000ms

Cause: Agent execution takes longer than the default timeout.

Fix: Increase the test timeout:

import { test } from "vitest";

test("slow agent test", async () => {
  // Test code here
}, 30000); // 30 second timeout

Signal assertion failed

Expected signals to contain "analysis:complete" but it was not found

Fix: Debug by logging all signals:

const result = await runReactive({ /* ... */ });

console.log("All signals:", result.signals.map(s => s.name));

expect(result.signals).toContainSignal("analysis:complete");

Recording/Replay Errors

Recording not found

Error: Recording 'rec_abc123' not found

Cause: Trying to replay a recording that doesn't exist.

Fix: Record first, then replay:

const store = new MemorySignalStore();

// Record
const result = await runReactive({
  agents: { analyzer },
  state: initialState,
  harness: new ClaudeHarness(),
  recording: { mode: "record", store },
});

const recordingId = result.recordingId;

// Replay with the same ID
const replay = await runReactive({
  agents: { analyzer },
  state: initialState,
  harness: new ClaudeHarness(),
  recording: { mode: "replay", store, recordingId },
});

Replay state mismatch

Error: Replay state doesn't match recorded state

Cause: Initial state differs from when recording was made.

Fix: Use the same initial state for replay:

const initialState = { input: "Hello", result: null };

// Same state for both
const record = await runReactive({
  state: initialState,
  recording: { mode: "record", store },
});

const replay = await runReactive({
  state: initialState, // Must match!
  recording: { mode: "replay", store, recordingId },
});

Debugging Tips

Enable signal tracing

const result = await runReactive({ /* ... */ });

// Log signal flow
for (const signal of result.signals) {
  console.log(`[${signal.timestamp}] ${signal.name}`, signal.payload);
}

Check agent activations

const activations = result.signals.filter(s => s.name === "agent:activated");
console.log("Agents that ran:", activations.map(s => s.payload.agent));

const skipped = result.signals.filter(s => s.name === "agent:skipped");
console.log("Agents skipped:", skipped.map(s => `${s.payload.agent}: ${s.payload.reason}`));

Inspect final state

console.log("Final state:", result.state);
console.log("Duration:", result.metrics.durationMs, "ms");
console.log("Agent activations:", result.metrics.activations);
console.log("Terminated early:", result.terminatedEarly);

Still Stuck?

If your error isn't listed here:

  1. Check the API Reference for correct function signatures
  2. Look at the Quickstart for working examples
  3. Review the Signal System for signal patterns

On this page