Skip to content
This repository was archived by the owner on Jun 3, 2026. It is now read-only.

fix: surface MaxTokensError when max_tokens truncates tool input JSON#1065

Open
cmbullock wants to merge 2 commits into
strands-agents:mainfrom
cmbullock:fix/1061/tool-use-truncated-syntax-error
Open

fix: surface MaxTokensError when max_tokens truncates tool input JSON#1065
cmbullock wants to merge 2 commits into
strands-agents:mainfrom
cmbullock:fix/1061/tool-use-truncated-syntax-error

Conversation

@cmbullock

Copy link
Copy Markdown

Description

streamAggregated currently throws a SyntaxError from JSON.parse of a truncated tool input buffer before the subsequent modelMessageStopEvent is processed. When the truncation was caused by maxTokens, the resulting ModelError carrying a SyntaxError cause obscures the actionable root cause - users see a misleading "Expected ',' or '}'..." parse error instead of the documented MaxTokensError path.

The same scenario surfaces MaxTokensReachedException correctly in the Python SDK - the TS SDK regressed in #680.

Related Issues

strands-agents/harness-sdk#2451

Documentation PR

  • N/A; brings ts SDK inline with documented behavior and python SDK

Type of Change

Bug fix

Testing

How have you tested the change?

  • I ran npm run check

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@cmbullock cmbullock temporarily deployed to manual-approval May 13, 2026 16:58 — with GitHub Actions Inactive
@github-actions github-actions Bot added the strands-running <strands-managed> Whether or not an agent is currently running label May 19, 2026
@mkmeral mkmeral self-assigned this May 19, 2026
@opieter-aws opieter-aws added the bug Something isn't working label May 19, 2026
await expect(async () => await collectGenerator(provider.streamAggregated(messages))).rejects.toThrow(
MaxTokensError
)
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Issue: Missing test coverage for the path where the stream ends without a modelMessageStopEvent while deferredToolInputParseError is set (i.e., the 'Stream ended without completing a message' error with the SyntaxError cause attached at line 477).

Suggestion: Add a test case where the generator yields a tool input delta + contentBlockStopEvent (triggering the parse error) but does NOT yield a modelMessageStopEvent. This exercises the new cause attachment on the "stream ended" error path.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Test added

Comment thread strands-ts/src/models/model.ts Outdated
}

if (deferredToolInputParseError !== undefined) {
throw deferredToolInputParseError

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Issue: When stopReason is not maxTokens, the deferred SyntaxError is thrown raw and relies on the outer catch block to wrap it in a ModelError. This produces a generic message like "Expected ',' or '}' in JSON at position X" rather than something actionable.

Suggestion: Consider wrapping it explicitly to preserve the diagnostic context already in the log message:

if (deferredToolInputParseError !== undefined) {
  throw new ModelError('unable to parse tool input JSON', { cause: deferredToolInputParseError })
}

This makes the error message self-descriptive and avoids depending on the outer catch's generic wrapping behavior.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Error explicitly wrapped and test updated

@github-actions

Copy link
Copy Markdown
Contributor

Assessment: Comment

Good fix that correctly surfaces MaxTokensError when tool input JSON is truncated due to token limits, aligning the TS SDK with the Python SDK behavior. The deferred-throw pattern is the right approach.

Review Details
  • Error wrapping: The non-maxTokens path throws a raw SyntaxError that gets implicitly wrapped by the outer catch block — works correctly but the resulting error message is generic rather than descriptive.
  • Test coverage: The two explicit scenarios (maxTokens and non-maxTokens) are well tested, but the intermediate path (stream ends without stop event + deferred parse error) could use a test for the new cause attachment.

Clean, minimal change that solves the reported issue.

@github-actions github-actions Bot removed the strands-running <strands-managed> Whether or not an agent is currently running label May 19, 2026
@cmbullock cmbullock deployed to manual-approval May 20, 2026 15:56 — with GitHub Actions Active
@strands-agent

Copy link
Copy Markdown
Collaborator

This repository has been merged into the strands-agents/harness-sdk monorepo and will be archived shortly. All new development happens there.

If this PR is still relevant, please recreate it against the monorepo. The code now lives under strands-ts/. Full commit history was preserved, so your base should be findable.

Apologies for the disruption, and thank you for contributing!

@github-actions github-actions Bot added the strands-running <strands-managed> Whether or not an agent is currently running label Jun 2, 2026
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Assessment: Approve

Both previous review comments have been addressed well. The error is now explicitly wrapped with a descriptive message, and the missing test case for the incomplete stream path has been added. All three error scenarios are properly tested and the logic is correct.

No further changes needed from a code quality perspective.

@github-actions github-actions Bot removed the strands-running <strands-managed> Whether or not an agent is currently running label Jun 2, 2026
})

it('preserves SyntaxError instead of overwriting with MaxTokensError when tool input JSON is malformed', async () => {
it('throws MaxTokenError when contentBlockStop arrives with truncated tool input JSON and stopReason is maxTokens', async () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: typo in the test description — MaxTokenError should be MaxTokensError (plural, matching the class in errors.ts). The assertion itself is correct; just the it(...) string.

@JackYPCOnline

Copy link
Copy Markdown
Contributor

@cmbullock Hi , thank you again for raising this PR.

  1. Could you please re-raise this PR in monorepo? Or I can cut the fix and mention you.
  2. Do you think rename this to be toolInputParseError make sense?

@cmbullock

cmbullock commented Jun 2, 2026

Copy link
Copy Markdown
Author
  1. Could you please re-raise this PR in monorepo? Or I can cut the fix and mention you.

I can probably get this taken care of in a few days - if you have an opportunity to first, please feel free to!

  1. Do you think rename this to be toolInputParseError make sense?

Absolutely, just a small oversight! 👍

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants