Skip to content

[superlog] Use warn level for AI tool errors within a request context#498

Open
superlog-app[bot] wants to merge 1 commit into
stagingfrom
superlog/fix-tool-logger-warn-on-request-context
Open

[superlog] Use warn level for AI tool errors within a request context#498
superlog-app[bot] wants to merge 1 commit into
stagingfrom
superlog/fix-tool-logger-warn-on-request-context

Conversation

@superlog-app

@superlog-app superlog-app Bot commented Jun 26, 2026

Copy link
Copy Markdown

Summary

Scheduled insights jobs were being logged at ERROR severity even when they completed successfully. The false-positive ERROR appeared whenever an AI tool call (e.g. a ClickHouse SQL query, an annotation create) failed inside the agent loop but the agent recovered and generated insights normally — job_status: "succeeded", run_status: "succeeded", generation_status: "succeeded" all appear in the same log event as "level":"error".

Evlog's wide event logger accumulates the highest severity seen within a request scope. createToolLogger.error() was calling requestLogger.error(err, {...}) on the job's wide event RequestLogger. Because the AI agent handles tool failures as normal tool-call results (the model receives the error and can try something else), these calls permanently tainted the job-level wide event to ERROR even on full success.

The fix changes the requestLogger call inside createToolLogger.error() from requestLogger.error(err) to requestLogger.warn(message). All tool error details remain in the context payload, and the fallback log.error() path (used outside any request context) is unchanged. The wide event for a fully successful job will now be emitted at INFO level, while genuinely failed jobs continue to reach ERROR through the job-level logger.error(err) catch block in jobs.ts.

An alternative approach would be to add a separate toolError() method to createToolLogger and update each call site. The single-point fix in the logger is preferable because all AI tool errors share the same recovery semantics.

Incident on Superlog


Was this PR helpful? Leave feedback — goes straight to the Superlog team.


Summary by cubic

Use warn level for tool-call failures within a request context so successful jobs no longer emit ERROR wide events. Error details remain in context; error-level logging outside a request context is unchanged.

  • Bug Fixes
    • Switched requestLogger.error(...) to requestLogger.warn(...) in createToolLogger.
    • Prevents recoverable tool failures from raising the job-wide severity.
    • Keeps log.error(...) behavior for non-request contexts.

Written for commit 3247b33. Summary will update on new commits.

Review in cubic

@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
databuddy-status Ready Ready Preview, Comment Jun 26, 2026 11:29pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
dashboard Skipped Skipped Jun 26, 2026 11:29pm
documentation Skipped Skipped Jun 26, 2026 11:29pm

@vercel vercel Bot temporarily deployed to Preview – documentation June 26, 2026 23:28 Inactive
@vercel vercel Bot temporarily deployed to Preview – dashboard June 26, 2026 23:28 Inactive
@unkey-deploy

unkey-deploy Bot commented Jun 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Unkey Deploy

Name Status Preview Inspect Updated (UTC)
api (preview) Ready Visit Preview Inspect Jun 26, 2026 11:29pm

@greptile-apps

greptile-apps Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes false-positive ERROR-level wide events in scheduled insights jobs by changing createToolLogger.error() to call requestLogger.warn() instead of requestLogger.error(new Error(message)) within a request context — preventing recoverable AI tool failures from permanently elevating the job's evlog wide event to ERROR when the agent successfully recovers.

  • The in-request path now logs tool errors at WARN, correctly scoping ERROR-level wide events to jobs whose job-level catch block fires. The fallback log.error() path (used outside a request scope) is intentionally unchanged.
  • The fix drops new Error(message) from the in-request path, silently losing stack trace information for tool errors in that context.
  • The error() method now has asymmetric severity behavior (WARN vs ERROR) depending on whether a request context is active, which could confuse future callers and inconsistently trigger monitoring rules.

Confidence Score: 4/5

The core fix is sound and directly addresses the false-positive ERROR logs, but the asymmetric severity between the two code paths in error() warrants a second look before merging.

The change is small and targeted. The in-request path now correctly emits WARN for recoverable tool failures, solving the described incident. However, toolLogger.error() now silently produces different log levels depending on execution context — WARN inside a request scope, ERROR outside it — which could mislead on-call engineers comparing logs from different invocation paths. Additionally, removing new Error(message) drops call-stack information from in-request tool errors, reducing debuggability for future incidents.

packages/ai/src/ai/tools/utils/logger.ts — specifically the behavioral split between the request-scoped and fallback branches of error().

Important Files Changed

Filename Overview
packages/ai/src/ai/tools/utils/logger.ts Changes createToolLogger.error() to call requestLogger.warn() instead of requestLogger.error(new Error(message)) within a request scope, fixing false-positive ERROR log elevations. The fallback log.error() path is intentionally unchanged. Removes stack trace capture; introduces an asymmetry where the same call site logs at different severity depending on whether a request context is active.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["toolLogger.error(message, context)"] --> B{getActiveAiRequestLogger}
    B -- "requestLogger present" --> C["requestLogger.warn(message, ...)"]
    B -- "no request context" --> D["log.error({...}) — unchanged"]
    C --> E["Wide event stays at INFO/WARN\nJob-level logger.error catches real failures"]
    D --> F["Emitted at ERROR level\n(background tasks, non-request paths)"]

    style C fill:#ffd966
    style D fill:#e06c75
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["toolLogger.error(message, context)"] --> B{getActiveAiRequestLogger}
    B -- "requestLogger present" --> C["requestLogger.warn(message, ...)"]
    B -- "no request context" --> D["log.error({...}) — unchanged"]
    C --> E["Wide event stays at INFO/WARN\nJob-level logger.error catches real failures"]
    D --> F["Emitted at ERROR level\n(background tasks, non-request paths)"]

    style C fill:#ffd966
    style D fill:#e06c75
Loading

Comments Outside Diff (2)

  1. packages/ai/src/ai/tools/utils/logger.ts, line 21-40 (link)

    P1 error() logs at different severity depending on execution context

    The same call to toolLogger.error() now produces WARN in the request-scoped path and ERROR via log.error() in the fallback path. When a tool error occurs outside a request context (e.g. during a standalone background invocation, a test, or a future code path that bypasses the request scope), the original ERROR-elevation problem is preserved. Callers can't know which severity they're getting, and alerting rules keyed on log.error will see opposite behavior depending on execution context — making incidents harder to reproduce and triage.

  2. packages/ai/src/ai/tools/utils/logger.ts, line 21-33 (link)

    P2 Stack trace dropped for in-request tool errors

    The original code did const err = new Error(message) and passed that Error object to requestLogger.error(err, ...), which preserves a stack trace. The new code passes only the message string to requestLogger.warn(...). For in-request tool failures, the call stack is now lost, which reduces the ability to pinpoint which tool invocation or code path produced the error when debugging.

Reviews (1): Last reviewed commit: "[superlog] Use warn level for AI tool er..." | Re-trigger Greptile

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.

0 participants