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 installCannot 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 vitestConfiguration 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 agentCause: 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 failedCause: 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.tsAuthentication
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 exceededCause: 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 functionCause: Vitest matchers not registered.
Fix: Add the setup file to your Vitest config:
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 5000msCause: 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 timeoutSignal assertion failed
Expected signals to contain "analysis:complete" but it was not foundFix: 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 foundCause: 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 stateCause: 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:
- Check the API Reference for correct function signatures
- Look at the Quickstart for working examples
- Review the Signal System for signal patterns