Skip to content

Fix: log list crashes with ZodError on self-hosted instances (CLI-20C) #1095

@MathurAditya724

Description

@MathurAditya724

Sentry Issue

CLI-20CZodError: Expected object, received string

Summary

sentry log list crashes with an unhandled ZodError when a self-hosted Sentry instance returns a non-object response (e.g., a plain text error or HTML page) for the /events/?dataset=logs endpoint. This typically happens when the self-hosted instance does not support the logs dataset or a reverse proxy intercepts the request.

Root Cause

The listLogs() function in src/lib/api/logs.ts uses LogsResponseSchema.parse(data) (which throws ZodError on failure) instead of .safeParse() (which returns an error object). This is the only API module in the codebase that uses raw .parse() — all others either use apiRequestToRegion with a schema: option (which does .safeParse() + wraps failures in ApiError) or have manual type checks.

How the API returns a string instead of an object

The @sentry/api SDK's HTTP client has response-parsing logic that depends on the Content-Type header:

  • Content-Type: text/html → SDK returns data = await response.text() (a raw HTML string)
  • Content-Type: text/plain → SDK returns data = await response.text() (a raw text string)
  • Content-Type: application/json with body "error message" → SDK returns the string from JSON.parse

unwrapResult() at infrastructure.ts:254 performs return data as T with no runtime type checking — it only checks if error is defined (which it isn't for 2xx responses).

Crash Site

// src/lib/api/logs.ts:130-132
const data = unwrapResult(result, "Failed to list logs");
const logsResponse = LogsResponseSchema.parse(data);  // <-- throws ZodError
return logsResponse.data;

Affected Functions

Both listLogs() (line 131) and getLogsBatch() (line ~194) have the identical vulnerable .parse() pattern.

Existing Pattern in the Codebase

The correct pattern already exists in src/lib/api/infrastructure.ts:477-493:

// apiRequestToRegion with schema option:
const result = schema.safeParse(data);
if (!result.success) {
  Sentry.setContext("zod_validation", { endpoint, status, issues });
  throw new ApiError("Unexpected response format from ...", status, result.error.message);
}

And in src/lib/api/organizations.ts:66-73:

if (!Array.isArray(data)) {
  throw new ApiError(
    "Failed to list organizations: unexpected response format",
    0,
    `Expected an array but received ${typeof data}. ` +
    "This may indicate an incompatible self-hosted Sentry version or a proxy interfering."
  );
}

Proposed Fix

  1. In src/lib/api/logs.ts, replace .parse() with .safeParse() + throw a descriptive ApiError with self-hosted-aware messaging — for both listLogs() and getLogsBatch()
  2. Add a pre-validation typeof data check for early, descriptive error messages (matching organizations.ts pattern)
  3. Add unit tests verifying that string/non-object responses produce a clear ApiError instead of an unhandled ZodError

Environment

  • Release: 0.36.0
  • Platform: node (self-hosted Sentry, Ubuntu Linux 24.04)
  • Command: sentry log list
  • Self-hosted: Yes (is_self_hosted: True)

Metadata

Metadata

Labels

bugSomething isn't workingjaredTrigger the Jared agent to work on stuff
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions