Skip to content

fix(logger, blocks): log nested errors and stop spurious model-selection warnings - #6706

Merged
waleedlatif1 merged 2 commits into
stagingfrom
fix/serializer-model-vars-and-blockoutputs-logging
Aug 14, 2026
Merged

fix(logger, blocks): log nested errors and stop spurious model-selection warnings#6706
waleedlatif1 merged 2 commits into
stagingfrom
fix/serializer-model-vars-and-blockoutputs-logging

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

Two chronic defects found while auditing production logs. Neither is release-related — both predate v0.8.1.

1. logger.x('msg', { error }) logged error: {} at 399 call sites.
mergeArgs copied object arguments verbatim, so an Error held under a key stayed an Error instance — and JSON.stringify renders that as {}, because message and stack are non-enumerable on Error.prototype. A bare Error argument was handled correctly; an error inside an object was not. This is why BlockOutputs :: Failed to get tool outputs (10k/week) was undiagnosable. The colorized/dev path had the same hole via formatObject, so a developer running locally saw the bug too.

  • Unwrap keyed Errors on both the structured and colorized paths.
  • error stays a plain message string so log queries can stats count(*) by error; richer diagnostics remain opt-in via describeError.

2. Router/Evaluator/Agent logged Invalid model selected ~140×/day.
config.tool resolved through getBaseModelProviders(), which deliberately excludes gateway providers (OpenRouter, vLLM, LiteLLM, Ollama, fireworks, together, baseten). So a fully valid openrouter/meta-llama/llama-4-maverick threw, as did a model still holding an unresolved <variable.x> at serialization time.

The serialized value is cosmetic — every one of these blocks re-derives the provider from the resolved model at execution (router-handler.ts:112, evaluator-handler.ts:177), and agent.ts already documented that it "never reads this serialized value". So the throw bought nothing and produced an error users cannot act on.

  • Resolve through getProviderFromModel, the same resolver the executor uses, so serialization and execution finally agree.
  • One shared helper replaces four near-identical inline implementations.
  • Drop the unreachable if (!model) checks sitting behind params.model || 'gpt-4o'.

Type of Change

  • Bug fix

Testing

1,189 tests pass across blocks, serializer, providers and executor handlers, plus the logger package; type-check and biome clean.

New tests, including two added specifically because review found the first pass insufficient:

  • Logger: keyed Error renders as its message on both paths; a non-conventional key doesn't hijack stack; sibling keys survive. Verified they fail without the fix with expected {} to be 'boom' — the exact production symptom.
  • Blocks: gateway model resolves; unresolved reference falls back; caller fallback honoured; never throws even when the resolver rejects every model (an env blacklist can reject the fallback too).
  • Providers: a test through the real resolver proving openrouter/* resolves via modelPatterns and that getBaseModelProviders() omits it — the mocked helper test alone would have passed even if the fix were deleted.

Notes

#2 has no user-facing impact — I checked before treating it as one. getToolParams returns undefined for both the provider id and the access[0] fallback (neither is a registered tool), so the dependent validation was skipped either way. This removes log noise and makes serialization agree with execution; it does not change behavior.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…ion warnings

Two production defects found in the prod logs, neither release-related.

logger: mergeArgs copied object arguments verbatim, so an Error held under a
key stayed an Error instance and JSON.stringify rendered it {} — message and
stack are non-enumerable on Error.prototype. 399 call sites use the
logger.x('msg', { error }) shape and every one logged error: {}, which is why
BlockOutputs failures (10k/week) were undiagnosable. The colorized path had
the same hole via formatObject.

blocks: router, evaluator and agent resolved config.tool through
getBaseModelProviders(), which deliberately excludes gateway providers
(OpenRouter, vLLM, LiteLLM, Ollama, ...). A valid openrouter/* model therefore
threw "Invalid model selected", as did a model still holding an unresolved
<variable.x> at serialization time — ~140 warnings/day. The value is cosmetic
(every handler re-derives the provider from the resolved model), so the throw
bought nothing.

- unwrap keyed Errors on both the structured and colorized log paths
- keep `error` a plain message string so log queries can group on it
- resolve serialized provider ids through getProviderFromModel, the same
  resolver the executor uses, via one shared helper for all four call sites
- drop the unreachable `if (!model)` checks behind `params.model || default`
@vercel

vercel Bot commented Aug 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Aug 14, 2026 8:40pm

Request Review

@cursor

cursor Bot commented Aug 14, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Changes are logging diagnostics and cosmetic serialization provider ids that execution re-derives; PR notes no user-facing behavior change for model selection.

Overview
Logger: logger.x('msg', { error }) and other object arguments that hold Error values now serialize with the real message (and stack on the structured path) instead of {}, on both JSON and colorized formatting paths. Sibling fields on the same object are preserved.

Model blocks: Agent, Router, and Evaluator config.tool no longer look up models in getBaseModelProviders() (which omits gateway providers and breaks on unresolved <variable> references). They use shared getSerializedModelProviderId, which resolves via getProviderFromModel, falls back for references/empty model, and never throws (last resort openai if resolution is blacklisted).

Tests: Coverage for gateway models, variable references, resolver failures, and the production error: {} symptom.

Reviewed by Cursor Bugbot for commit 523a67f. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR improves nested Error serialization in structured and colorized logs and aligns serialized model-provider selection with the resolver used by model-driven blocks.

  • Converts keyed Error values into useful message and stack data while preserving sibling fields.
  • Adds a shared, non-throwing provider-resolution helper for Agent, Evaluator, and Router blocks.
  • Adds regression coverage for nested errors, gateway providers, unresolved model references, and blacklisted fallbacks.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
packages/logger/src/index.ts Adds shared Error normalization and applies it to keyed errors in structured and colorized logging paths.
apps/sim/blocks/utils.ts Adds a documented, non-throwing serialization-time model-provider resolver with explicit fallbacks.
apps/sim/blocks/blocks/agent.ts Uses the shared provider resolver while retaining the Agent block’s auto-model fallback behavior.
apps/sim/blocks/blocks/evaluator.ts Replaces base-model-map validation with shared serialization-time provider resolution.
apps/sim/blocks/blocks/router.ts Applies shared provider resolution to both legacy and current Router block configurations.

Reviews (2): Last reviewed commit: "fix(blocks): move the fallback rationale..." | Re-trigger Greptile

Comment thread apps/sim/blocks/utils.ts Outdated
The repo forbids non-TSDoc comments; the explanation for why recovery returns
a constant instead of resolving again belongs on the declaration anyway.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 523a67f. Configure here.

@waleedlatif1
waleedlatif1 merged commit af076a7 into staging Aug 14, 2026
30 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/serializer-model-vars-and-blockoutputs-logging branch August 14, 2026 21:41
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.

1 participant