vercel / vercel/workflow

Serde checker false-positive: warns for classes tree-shaken out of the workflow bundle (AI SDK models used only inside steps)

Open
#2,956 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
2.4k
Forks
365
Avg merge
2d 11h
Merged PRs (30d)
169

Description

False-positive serde warning for AI SDK model classes that were tree-shaken out of the workflow bundle

TL;DR

since workflow > 4.3.1 && < 5.0.0-beta.35
You are getting this scary warning.

> nitro dev

➜ Listening on: http://localhost:3000/ (all interfaces)
⚠ Serde warning for classes "OpenAIChatLanguageModel", "OpenAICompletionLanguageModel", "OpenAIEmbeddingModel", "OpenAIImageModel", "OpenAIResponsesLanguageModel", "OpenAISpeechModel", "OpenAITranscriptionModel", "GatewayEmbeddingModel", "GatewayImageModel", "GatewayLanguageModel": No class registration IIFE was generated. Ensure WORKFLOW_SERIALIZE and WORKFLOW_DESERIALIZE are defined as static methods inside the class body using computed property syntax: static [WORKFLOW_SERIALIZE](...) { ... }
workflows build complete (79 steps, 16 workflows, time 769ms)
ℹ Starting dev watcher (builder: rolldown, preset: nitro-dev, compatibility date: 2026-07-16)               nitro 3:27:57 PM
✔ Server built in 136ms

[!IMPORTANT]
Below is an issue analysis made by Claude Fable 5

Summary

analyzeSerdeCompliance warns No class registration IIFE was generated for every AI SDK model class, even when those classes never appear in the final workflow bundle. The manifest of serde-capable classes is collected during the SWC scan (pre-DCE), but the registration-IIFE check runs against the post-DCE bundle text — so when the classes are only used inside "use step" bodies (the recommended pattern) and get tree-shaken out of the workflow bundle, the checker still flags all of them.

The warning's suggested fix is also misleading: the flagged classes do define static [WORKFLOW_SERIALIZE] / static [WORKFLOW_DESERIALIZE] with computed property syntax in the shipped dist of the AI SDK packages, exactly as the message asks. There is nothing an app author (or the library author) can change to make the warning go away.

Warning output

⚠ Serde warning for classes "OpenAIChatLanguageModel", "OpenAICompletionLanguageModel", "OpenAIEmbeddingModel", "OpenAIImageModel", "OpenAIResponsesLanguageModel", "OpenAISpeechModel", "OpenAITranscriptionModel", "GatewayEmbeddingModel", "GatewayImageModel", "GatewayLanguageModel": No class registration IIFE was generated. Ensure WORKFLOW_SERIALIZE and WORKFLOW_DESERIALIZE are defined as static methods inside the class body using computed property syntax: static [WORKFLOW_SERIALIZE](...) { ... }

Environment

  • workflow: 4.6.0 (@workflow/builders / @workflow/nitro: 4.0.9)
  • ai: 7.0.29 (bundles @ai-sdk/gateway 4.0.21)
  • @ai-sdk/openai: 4.0.15
  • Framework: Nitro 3.0.260311-beta via the workflow/nitro module
  • Node: v26.4.0

Reproduction

Any Nitro (likely any framework) project where an AI SDK model is instantiated and consumed entirely inside a step — i.e. the model instance never crosses a step/workflow boundary:

// workflows/example/steps.ts
import { openai } from "@ai-sdk/openai";
import { generateText } from "ai";

export async function classify(input: string) {
  "use step";
  const { text } = await generateText({
    model: openai("gpt-5-nano"), // created and used only inside the step
    prompt: input,
  });
  return text;
}
// workflows/example/index.ts
import { classify } from "./steps";

export async function exampleWorkflow(input: string) {
  "use workflow";
  return classify(input);
}

Run nitro dev (or build) → the warning above is printed, once per serde-capable class in the dependency graph.

What actually happens

  1. During the workflow-bundle build, the SWC transform records every class implementing the serde protocol into workflowManifest.classes. The AI SDK model classes are picked up because @ai-sdk/openai / @ai-sdk/gateway ship static [WORKFLOW_SERIALIZE] / static [WORKFLOW_DESERIALIZE] in their dist.
  2. Because the models are only referenced inside "use step" bodies, step stripping + dead-code elimination removes them from the workflow bundle entirely. Verified on our build output: the generated workflows.mjs contains 0 occurrences of OpenAIChatLanguageModel (or any of the other flagged classes) and 0 occurrences of Symbol.for("workflow-class-registry").
  3. analyzeSerdeCompliance (@workflow/builders/dist/serde-checker.js) then computes a single boolean — hasRegistration = /Symbol\.for\s*\(\s*["']workflow-class-registry["']\s*\)/.test(workflowCode) — over the whole bundle, and since no registration IIFE exists anywhere (correctly, as no serde class survived DCE), it emits the "No class registration IIFE was generated" issue for every class in the manifest (base-builder.js, the analyzeSerdeCompliance call after the interim bundle is built).

So the check compares a pre-DCE class inventory against a post-DCE bundle, with no per-class presence check in between.

Why this matters

  • The recommended pattern for using AI SDK models in workflows — instantiate the model inside the step that uses it — is precisely the pattern that triggers the warning. Users doing the right thing get 10 scary-looking warnings on every dev/build.
  • The remediation text points users at a fix that is impossible to apply (the statics are already defined correctly in the AI SDK dist), sending them down a rabbit hole toward the AI SDK instead of nowhere.
  • There is no supported way to suppress it: the console.warn in base-builder.js is unconditional (suppressCreateWorkflowsBundleWarnings only covers esbuild messages).

Suggested fix

Before reporting a class as non-compliant, check that the class actually survived into the workflow bundle — e.g. only warn for a manifest entry whose className (or classId) appears in workflowCode, or track survival through DCE explicitly. Classes that were tree-shaken out can never be deserialized at runtime, so a missing registration for them is not an issue.

Alternatively (or additionally), split the warning texts: "class present in bundle but not registered" (actionable, current message) vs. informational/silent for "serde-capable class detected in dependencies but not part of the workflow bundle".

Happy to provide the full debug manifest (workflows.mjs.debug.json) or a minimal repro repo if useful.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in @workflow/builders/dist/serde-checker.js at analyzeSerdeCompliance and trace its call from base-builder.js after the interim bundle is built. Compare the manifest entries with workflowCode, using the reported tree-shaken AI SDK reproduction and debug manifest if needed. Done means warnings are limited to serde classes present in the workflow bundle, while classes that survive without registration remain actionable.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
build-system, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.