Skip to content

fix(core): clarify structured output errors after tool steps#1146

Merged
omeraplak merged 2 commits intomainfrom
fix/issue-1145-structured-output-error
Mar 9, 2026
Merged

fix(core): clarify structured output errors after tool steps#1146
omeraplak merged 2 commits intomainfrom
fix/issue-1145-structured-output-error

Conversation

@omeraplak
Copy link
Member

@omeraplak omeraplak commented Mar 9, 2026

PR Checklist

Please check if your PR fulfills the following requirements:

Bugs / Features

What is the current behavior?

When Agent.generateText is called with a structured output (e.g. Output.object(...)) and tool-enabled runs end without a final output payload, callers can hit a vague AI_NoOutputGeneratedError later.

What is the new behavior?

Agent.generateText now validates structured output availability immediately when output is requested.

If no final output is generated, it throws a descriptive VoltAgentError with:

  • code: STRUCTURED_OUTPUT_NOT_GENERATED
  • stage: response_parsing
  • metadata including finish reason, step count, max steps, and tool call counts.

Also adds an unhandled-rejection hint in VoltAgent logs for the AI_NoOutputGeneratedError case.

fixes #1145

Notes for reviewers

  • Added regression test in packages/core/src/agent/agent.spec.ts for missing structured output.
  • Added changeset: .changeset/curly-oranges-double.md.
  • Verified with:
    • pnpm --filter @voltagent/core exec vitest run src/agent/agent.spec.ts --reporter=dot

Summary by cubic

Improve structured output handling in Agent.generateText when tool-enabled runs end without a final payload. Calls now fail fast with a clear, retryable VoltAgentError, enabling fallback to the next model. Fixes #1145.

  • Bug Fixes
    • Validate structured output immediately when output is requested; if missing, throw VoltAgentError (STRUCTURED_OUTPUT_NOT_GENERATED) with finish reason, steps, max steps, configured tool count, and tool call count, and treat it as retryable for model fallback.
    • Add an unhandled-rejection hint in VoltAgent logs for missing structured outputs to guide emitting a final schema-matching response or splitting into two calls.

Written for commit acdb306. Summary will update on new commits.

Summary by CodeRabbit

  • Bug Fixes

    • Improved error handling when structured output is not produced: users now see clearer messages including finish reason and step/tool metadata for easier debugging.
    • Added log hints for missing structured outputs to surface guidance without crashing.
    • Improved retry/fallback behavior so secondary model responses can be used when the primary fails to emit structured output.
  • Tests

    • Added tests covering structured-output error scenarios and fallback behavior.

@changeset-bot
Copy link

changeset-bot bot commented Mar 9, 2026

🦋 Changeset detected

Latest commit: acdb306

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@voltagent/core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@joggrbot

This comment has been minimized.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 9, 2026

📝 Walkthrough

Walkthrough

Detects when a structured output is requested but the model fails to emit a final output; Agent now inspects result.output immediately, collects finish/step/tool metadata, and throws a descriptive VoltAgentError (STRUCTURED_OUTPUT_NOT_GENERATED). Unhandled rejection logs also include a hint for this case.

Changes

Cohort / File(s) Summary
Changelog
\.changeset/curly-oranges-double.md
Adds changelog entry describing improved structured-output error handling and logging hint for missing final outputs.
Tests
packages/core/src/agent/agent.spec.ts
Adds unit tests asserting descriptive error when structured output is missing and tests fallback behavior when a secondary model returns structured output.
Agent core
packages/core/src/agent/agent.ts
Adds private ensureStructuredOutputGenerated(...) to access result.output, detect NoOutputGeneratedError, collect finish/tool/step metadata, and throw VoltAgentError with guidance; invokes this check after generateText. Marks the new error as retryable.
Agent runtime logging
packages/core/src/voltagent.ts
Extends unhandled-rejection handling to detect NoOutputGeneratedError (including wrapped variants) and attach a user-facing hint to logs for debugging structured-output failures.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Agent
  participant Model
  participant Tools
  participant FallbackModel

  Client->>Agent: generateText(input, { output: schema })
  Agent->>Model: call generateText(...)
  Note right of Model: may produce tool calls and/or final output
  Model->>Tools: (optional) invoke tool(s)
  Tools-->>Model: toolResults
  Model-->>Agent: GenerateTextResult (lazy result.output getter)
  Agent->>Agent: ensureStructuredOutputGenerated(result, output, tools, maxSteps)
  alt result.output access throws NoOutputGeneratedError
    Agent->>Agent: collect tool call metadata, finishReason, stepCount
    Agent-->>Client: throw VoltAgentError(STRUCTURED_OUTPUT_NOT_GENERATED, metadata)
    Note over Agent,Client: If configured, Agent may retry using FallbackModel
    Agent->>FallbackModel: call generateText(...) (fallback)
    FallbackModel-->>Agent: valid structured GenerateTextResult
    Agent-->>Client: return parsed structured output
  else result.output accessed successfully
    Agent-->>Client: return structured output
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 I nibbled through outputs, sniffed the trail,
When final schema vanished, I left a bright trail.
With finish-reasons, steps, and hints in tow,
No more cryptic hops where errors grow.
A rabbit's cheer — structured outputs now show! 🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: improving structured output error clarity after tool steps.
Description check ✅ Passed The description comprehensively covers current/new behavior, checklist completion, testing, changesets, and includes issue reference with detailed notes for reviewers.
Linked Issues check ✅ Passed All primary objectives from issue #1145 are met: structured output validation occurs immediately [agent.ts], clear VoltAgentError with STRUCTURED_OUTPUT_NOT_GENERATED is thrown [agent.ts], error includes finish reason and step metadata [agent.ts], unhandled-rejection hint added [voltagent.ts], and error is retryable for fallback [agent.ts].
Out of Scope Changes check ✅ Passed All changes align with issue #1145 scope: structured output validation, error clarity, metadata inclusion, logging hints, and retry handling for tool-enabled runs.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/issue-1145-structured-output-error

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 4 files

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/agent/agent.ts`:
- Around line 1211-1216: The structured-output validation
(ensureStructuredOutputGenerated) currently runs after executeWithModelFallback
returns, which allows STRUCTURED_OUTPUT_NOT_GENERATED to bypass retries; move
the call into the fallback/retry loop so validation happens for each model
attempt: call ensureStructuredOutputGenerated (with result, output, tools,
maxSteps) inside executeWithModelFallback's per-attempt logic (or immediately
before an attempt returns success) and treat STRUCTURED_OUTPUT_NOT_GENERATED as
a retryable failure so the fallback loop can try the next model instead of
returning immediately.

In `@packages/core/src/voltagent.ts`:
- Around line 435-444: The unhandled-rejection hint check only detects
NoOutputGeneratedError (and AI_NoOutputGeneratedError) but not the wrapper
VoltAgentError; update the isNoOutputGeneratedError condition in voltagent.ts to
also consider instances of VoltAgentError whose code ===
"STRUCTURED_OUTPUT_NOT_GENERATED" (the wrapper created by Agent.generateText),
so the hint is shown when the structured-output error is wrapped.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fc610b7f-5113-4d47-a8fe-b25460cf8fee

📥 Commits

Reviewing files that changed from the base of the PR and between 13f5a9e and a6ec1ba.

📒 Files selected for processing (4)
  • .changeset/curly-oranges-double.md
  • packages/core/src/agent/agent.spec.ts
  • packages/core/src/agent/agent.ts
  • packages/core/src/voltagent.ts

@cloudflare-workers-and-pages
Copy link

Deploying voltagent with  Cloudflare Pages  Cloudflare Pages

Latest commit: a6ec1ba
Status: ✅  Deploy successful!
Preview URL: https://396ea85d.voltagent.pages.dev
Branch Preview URL: https://fix-issue-1145-structured-ou.voltagent.pages.dev

View logs

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/agent/agent.ts`:
- Around line 1195-1200: The code is retrying STRUCTURED_OUTPUT_NOT_GENERATED
after generateText(...) has already executed step callbacks and side-effecting
tools, which can cause duplicate/stale ConversationBuffer, conversationSteps,
and tool outputs; modify the fallback/retry behavior so that before retrying
when ensureStructuredOutputGenerated(...) raises STRUCTURED_OUTPUT_NOT_GENERATED
you call resetOperationAttemptState(...) on the current OperationContext to
clear per-attempt state (ConversationBuffer, conversationSteps, tool execution
markers) OR instead mark STRUCTURED_OUTPUT_NOT_GENERATED as terminal once any
tool steps have executed; update the logic around
ensureStructuredOutputGenerated, the STRUCTURED_OUTPUT_NOT_GENERATED handling
(referenced at lines with STRUCTURED_OUTPUT_NOT_GENERATED), and where
generateText(...) completes to either resetAttempt state or make the error
non-retryable to prevent re-executing tools on the same OperationContext.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3149c9c6-e547-43aa-a901-43a5d6e9e63a

📥 Commits

Reviewing files that changed from the base of the PR and between a6ec1ba and acdb306.

📒 Files selected for processing (3)
  • packages/core/src/agent/agent.spec.ts
  • packages/core/src/agent/agent.ts
  • packages/core/src/voltagent.ts

Comment on lines +1195 to +1200
this.ensureStructuredOutputGenerated({
result: response,
output,
tools,
maxSteps,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid recovering structured-output failures on a dirty attempt state.

By Line 1195, generateText(...) has already finished running step callbacks, so the failed attempt may have populated ConversationBuffer, conversationSteps, and executed tools. Because Lines 5264-5266 make STRUCTURED_OUTPUT_NOT_GENERATED retryable, the fallback loop can now rerun the request on the same OperationContext without any resetOperationAttemptState(...), which means a recovered attempt can re-execute side-effecting tools and later persist stale tool/result messages from the failed run.

Please either reset per-attempt state before retry/fallback for this error class, or keep this error terminal once tool steps have already executed.

Also applies to: 5264-5266

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/agent/agent.ts` around lines 1195 - 1200, The code is
retrying STRUCTURED_OUTPUT_NOT_GENERATED after generateText(...) has already
executed step callbacks and side-effecting tools, which can cause
duplicate/stale ConversationBuffer, conversationSteps, and tool outputs; modify
the fallback/retry behavior so that before retrying when
ensureStructuredOutputGenerated(...) raises STRUCTURED_OUTPUT_NOT_GENERATED you
call resetOperationAttemptState(...) on the current OperationContext to clear
per-attempt state (ConversationBuffer, conversationSteps, tool execution
markers) OR instead mark STRUCTURED_OUTPUT_NOT_GENERATED as terminal once any
tool steps have executed; update the logic around
ensureStructuredOutputGenerated, the STRUCTURED_OUTPUT_NOT_GENERATED handling
(referenced at lines with STRUCTURED_OUTPUT_NOT_GENERATED), and where
generateText(...) completes to either resetAttempt state or make the error
non-retryable to prevent re-executing tools on the same OperationContext.

@omeraplak omeraplak merged commit c7b4c45 into main Mar 9, 2026
23 checks passed
@omeraplak omeraplak deleted the fix/issue-1145-structured-output-error branch March 10, 2026 00:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] AI_NoOutputGeneratedError when using Agent.generateText with both tools and Output.object

1 participant