Troubleshooting
Common issues and their solutions when using temporal-contract.
Connection Issues
"Connection refused" or "ECONNREFUSED"
Symptoms:
Error: connect ECONNREFUSED 127.0.0.1:7233Cause: Temporal server is not running or not accessible at the specified address.
Solutions:
Check if Temporal is running:
bash# Using Docker docker ps | grep temporal # Check if port 7233 is listening netstat -an | grep 7233 # or lsof -i :7233Start Temporal:
bash# Using Temporal CLI temporal server start-dev # Or using Docker Compose docker-compose up -d temporalVerify connection address:
typescript// ✅ Correct format const connection = await Connection.connect({ address: "localhost:7233" }); // ❌ Common mistakes const connection = await Connection.connect({ address: "localhost" }); // Missing port const connection = await Connection.connect({ address: "http://localhost:7233" }); // Protocol not neededCheck firewall/network:
bash# Test connection telnet localhost 7233 # or nc -zv localhost 7233
"Namespace not found"
Symptoms:
Error: Namespace "my-namespace" not foundCause: The namespace doesn't exist in Temporal.
Solutions:
Create the namespace:
bash# Using Temporal CLI temporal operator namespace create my-namespaceUse default namespace:
typescript// Default namespace is "default" const client = new Client({ connection, namespace: "default", });Check Temporal Web UI:
- Open http://localhost:8233
- Verify namespace exists under "Namespaces"
TypeScript Errors
"Type 'X' is not assignable to type 'Y'"
Symptoms:
Type '{ orderId: string; }' is not assignable to type 'OrderInput'.
Property 'customerId' is missing.Cause: Workflow input doesn't match the schema defined in your contract.
Solution: Provide all required fields:
// ❌ Missing required field
client.executeWorkflow("processOrder", {
workflowId: "order-123",
args: {
orderId: "ORD-123",
// Missing 'customerId' and 'amount'
},
});
// ✅ All required fields
client.executeWorkflow("processOrder", {
workflowId: "order-123",
args: {
orderId: "ORD-123",
customerId: "CUST-456",
amount: 99.99,
},
});"Property 'X' does not exist on type 'Y'"
Symptoms:
Property 'transactionId' does not exist on type 'never'.Cause: TypeScript cannot infer types properly from the contract.
Solutions:
Ensure contract is properly typed:
typescript// ✅ Export contract as const export const contract = defineContract({ // ... }); // ❌ Don't use 'any' or lose type information export const contract: any = defineContract({ // ... });Use correct type inference:
typescriptimport type { InferWorkflowInput } from "@temporal-contract/contract"; import { contract } from "./contract.js"; type OrderInput = InferWorkflowInput<typeof contract, "processOrder">;Check activity handler types:
typescript// ✅ Input is automatically typed activities: { processOrder: { processPayment: ({ customerId, amount }) => { console.log(customerId); // Type-safe! return Future.value(Result.Ok({ transactionId: "tx-123" })); }, }, }
"Cannot find module" or "Module not found"
Symptoms:
Error [ERR_MODULE_NOT_FOUND]: Cannot find module './contract'Cause: Missing .js extension in imports (required for ESM).
Solution: Always use .js extensions:
// ❌ Missing extension
import { contract } from "./contract";
// ✅ With extension
import { contract } from "./contract.js";TIP
Even though your file is contract.ts, you must import it as contract.js when using ESM!
"moduleResolution" or "module" errors
Symptoms:
Module resolution kind 'Node' is not supported for ES6 module output.Cause: Incorrect TypeScript configuration.
Solution: Update tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"strict": true
}
}Validation Errors
"Validation failed: expected string, received number"
Symptoms:
Error: Validation failed: [
{
"code": "invalid_type",
"expected": "string",
"received": "number",
"path": ["orderId"]
}
]Cause: Workflow input doesn't match the Zod/Valibot/ArkType schema.
Solution: Ensure data types match the schema:
// Schema
const contract = defineContract({
taskQueue: "orders",
workflows: {
processOrder: {
input: z.object({
orderId: z.string(),
amount: z.number(),
}),
// ...
},
},
});
// ❌ Wrong types
client.executeWorkflow("processOrder", {
workflowId: "order-123",
args: {
orderId: 123, // Should be string!
amount: "99.99", // Should be number!
},
});
// ✅ Correct types
client.executeWorkflow("processOrder", {
workflowId: "order-123",
args: {
orderId: "ORD-123", // String
amount: 99.99, // Number
},
});"Required field missing"
Symptoms:
Error: Validation failed: [
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": ["customerId"]
}
]Cause: Starting workflow with missing required fields.
Solution: Provide all required fields in the schema.
Worker Issues
"Task queue not found" or "No worker polling"
Symptoms:
- Workflow hangs and doesn't progress
- Activities never execute
- Timeout errors
Cause: No worker is polling the task queue.
Solutions:
Start the worker:
typescriptconst worker = await Worker.create({ workflowsPath: require.resolve("./workflows"), activities, taskQueue: contract.taskQueue, }); await worker.run();Verify task queue matches:
typescript// Contract const contract = defineContract({ taskQueue: "orders", // ⚠️ Must match worker // ... }); // Worker const worker = await Worker.create({ taskQueue: "orders", // ⚠️ Must match contract // ... });Check Temporal Web UI:
- Open http://localhost:8233
- Go to workflow -> Task Queue
- Verify workers are polling
"Activity execution failed"
Symptoms:
Error: Activity task failed: ActivityErrorCause: Activity threw an error or returned an error result.
Solutions:
Check activity implementation:
typescript// ✅ Return proper error result processPayment: ({ customerId, amount }) => { return Future.fromPromise(paymentService.charge(customerId, amount)) .mapOk((tx) => ({ transactionId: tx.id })) .mapError((e) => new ActivityError("PAYMENT_FAILED", e.message, e)); };Handle errors in workflow:
typescriptimplementation: async ({ activities }, input) => { try { const payment = await activities.processPayment(input); return { status: "success", transactionId: payment.transactionId }; } catch (error) { // Handle activity failure return { status: "failed", transactionId: undefined }; } };Configure retries:
typescript// Activities automatically retry by default // Check Temporal retry policies if needed
"Workflow bundle not found"
Symptoms:
Error: Cannot find module './workflows'Cause: Workflow file path is incorrect or not bundled.
Solutions:
Use correct path:
typescript// ✅ Use require.resolve for correct path const worker = await Worker.create({ workflowsPath: require.resolve("./workflows"), // ... });Ensure workflows export correctly:
typescript// workflows.ts - export all workflows export { processOrder } from "./processOrder.js"; export { cancelOrder } from "./cancelOrder.js";Check build output:
- Ensure TypeScript compiles workflows
- Check that output directory contains workflow files
Result/Future Pattern Issues
"Cannot read property 'match' of undefined"
Symptoms:
TypeError: Cannot read property 'match' of undefinedCause: Activity returned undefined instead of a Result.
Solution: Always return a Future/Result from activities:
// ❌ Returns undefined
processPayment: () => {
paymentService.charge();
// No return!
};
// ✅ Returns Future<Result>
processPayment: ({ customerId, amount }) => {
return Future.fromPromise(paymentService.charge(customerId, amount))
.mapOk((tx) => ({ transactionId: tx.id }))
.mapError((e) => new ActivityError("PAYMENT_FAILED", e.message));
};"Result.Ok is not a function"
Symptoms:
TypeError: Result.Ok is not a functionCause: Importing from wrong package or incorrect import.
Solution: Use correct imports:
// ✅ For activities (use @swan-io/boxed for performance)
import { Future, Result } from "@swan-io/boxed";
// ✅ For client results (temporal-contract internal)
import { Result } from "@temporal-contract/boxed";Performance Issues
Slow workflow execution
Symptoms:
- Workflows take longer than expected
- High latency between activities
- Worker resource exhaustion
Solutions:
Optimize activity implementation:
typescript// ❌ Blocking operation processOrder: ({ payload }) => { return Future.fromPromise(fetch("http://slow-api.com/process")); }; // ✅ Add timeouts and handle slow operations processOrder: ({ payload }) => { return Future.fromPromise( Promise.race([ fetch("http://api.com/process"), new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), 5000)), ]), ); };Configure worker capacity:
typescriptconst worker = await Worker.create({ // ... maxConcurrentActivityTaskExecutions: 100, maxConcurrentWorkflowTaskExecutions: 100, });Use async activities appropriately:
- Long-running operations should use heartbeats
- Consider breaking large workflows into child workflows
Memory issues
Symptoms:
- Worker memory grows over time
- Out of memory errors
Solutions:
Limit concurrent executions:
typescriptconst worker = await Worker.create({ // ... maxConcurrentActivityTaskExecutions: 50, // Lower if memory constrained maxConcurrentWorkflowTaskExecutions: 50, });Graceful shutdown:
typescriptprocess.on("SIGINT", async () => { await worker.shutdown(); process.exit(0); });
Still Having Issues?
If your problem isn't listed here:
Check GitHub Issues:
Review Documentation:
Check Examples:
Temporal Resources:
Need More Help?
When asking for help, please provide:
- temporal-contract version (check
package.json) - Node.js version (
node --version) - TypeScript version (
npx tsc --version) - Temporal server version
- Complete error message and stack trace
- Minimal reproduction code