How to Fix 'state not updating during development' in CrewAI (TypeScript)

By Cyprian AaronsUpdated 2026-04-21
state-not-updating-during-developmentcrewaitypescript

When CrewAI says “state not updating during development”, it usually means your agent or workflow is holding onto stale in-memory state while your TypeScript dev server hot-reloads modules. You’ll see it when tasks keep using old values, memory looks frozen, or a crew run behaves differently after code changes than after a full restart.

This is usually not a CrewAI bug. It’s almost always a lifecycle problem: singleton instances, cached module state, or a dev server that reuses objects across reloads.

The Most Common Cause

The #1 cause is creating your Crew, Agent, or shared state at module scope and then expecting edits to be picked up during development.

That pattern works once, then breaks under hot reload because the old instance stays alive in memory. In TypeScript projects using tsx, ts-node-dev, Next.js, or Vite-backed tooling, this is the first thing to check.

Broken vs fixed pattern

Broken patternFixed pattern
Instantiate once at import timeCreate fresh instances per run
Shared mutable state outside the functionState passed into the run function
Hot reload reuses stale objectsEach execution gets a clean object graph
// ❌ Broken: module-level singleton keeps stale state
import { Agent, Crew, Task } from "@crew-ai/crewai";

let runCount = 0;

const analyst = new Agent({
  role: "Analyst",
  goal: "Summarize input",
  backstory: "You are precise.",
});

const task = new Task({
  description: `Run number ${runCount}`,
  agent: analyst,
});

const crew = new Crew({
  agents: [analyst],
  tasks: [task],
});

export async function runCrew() {
  runCount++;
  return crew.kickoff();
}
// ✅ Fixed: build everything inside the execution path
import { Agent, Crew, Task } from "@crew-ai/crewai";

export async function runCrew(input: string) {
  const analyst = new Agent({
    role: "Analyst",
    goal: "Summarize input",
    backstory: "You are precise.",
  });

  const task = new Task({
    description: `Summarize this input: ${input}`,
    agent: analyst,
  });

  const crew = new Crew({
    agents: [analyst],
    tasks: [task],
  });

  return crew.kickoff();
}

If you need shared config, share data, not live instances. Keep Agent, Task, and Crew construction inside a factory function so every invocation starts clean.

Other Possible Causes

1) Dev server cache is preserving old compiled output

If you’re using a watcher with aggressive caching, you may be running code that no longer matches your source.

{
  "scripts": {
    "dev": "tsx watch src/index.ts"
  }
}

Try clearing build artifacts and restarting:

rm -rf dist .turbo .next node_modules/.cache
npm run dev

If the issue disappears after a cold start, it’s cache-related.

2) Mutating objects passed into tasks

CrewAI tasks can read stale values if you mutate an object after creating the task instead of passing a fresh payload.

// ❌ Broken
const payload = { customerId: "123", status: "new" };

const task = new Task({
  description: `Process customer ${payload.customerId} with status ${payload.status}`,
  agent,
});

payload.status = "approved";
// ✅ Fixed
const task = new Task({
  description: `Process customer ${customerId} with status ${status}`,
  agent,
});

Use primitives or immutable snapshots when building prompts and task descriptions.

3) Reusing one memory store across runs

If you connect CrewAI to external memory or your own in-memory store, it may persist state between runs during development.

// ❌ Broken
const memoryStore = new Map<string, unknown>();

export function getMemory() {
  return memoryStore;
}

Reset per request or per test:

// ✅ Fixed
export function createMemoryStore() {
  return new Map<string, unknown>();
}

For debugging, log whether the memory object identity changes between runs.

4) Environment variables loaded too early

If .env values are read at import time, hot reload can keep old config around even after you change the file.

// ❌ Broken
const modelName = process.env.CREWAI_MODEL ?? "gpt-4o-mini";

Load config inside startup code:

// ✅ Fixed
export function getConfig() {
  return {
    modelName: process.env.CREWAI_MODEL ?? "gpt-4o-mini",
  };
}

If you changed .env, restart the process. Most watchers do not fully reload environment state.

How to Debug It

  1. Check whether instances are created once or per run

    • Search for new Crew(, new Agent(, and new Task( at file scope.
    • If they are outside a function, move them inside the execution path.
  2. Log object identity

    • Add temporary logs for each run:
    console.log("crew instance", crew);
    console.log("task description", task.description);
    
    • If the same instance survives across edits, hot reload is reusing stale state.
  3. Restart with caches cleared

    • Stop the watcher.
    • Delete build caches.
    • Start again from a cold boot.
    • If the issue vanishes, your problem is dev-server persistence rather than CrewAI logic.
  4. Reduce to a minimal file

    • Remove memory layers, custom wrappers, and helper factories.
    • Keep only one agent and one task.
    • If the bug disappears in the minimal version, add pieces back until it breaks again.

Prevention

  • Build Crew, Agent, and Task objects inside functions that execute per request or per job.
  • Treat prompt inputs as immutable snapshots; don’t mutate shared objects after task creation.
  • Use explicit restart steps in your dev workflow when changing .env, model config, or memory wiring.

If you’re seeing errors like CrewAIError, stale outputs after edits, or behavior that only fixes itself on restart, assume lifecycle first and framework second. In TypeScript projects, “state not updating during development” is usually just stale module state wearing a CrewAI mask.


Keep learning

By Cyprian Aarons, AI Consultant at Topiax.

Want the complete 8-step roadmap?

Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.

Get the Starter Kit

Related Guides