Skip to content

Subprocess backends discard the analyzer's stderr when it exits 0 without writing analysis.json #355

Description

@rahlk

Problem

When a subprocess analyzer exits 0 but writes no analysis.json, the SDK raises

CodeanalyzerExecutionException: codeanalyzer-typescript did not generate analysis.json.

and discards the analyzer's own diagnostic, which is the only thing that says why. The run is captured (capture_output=True) and then thrown away.

Hit for real on a whole-repo TypeScript analysis: the analyzer printed

[codeanalyzer-ts] FATAL TypeError: Type error
    at structuredClone (unknown)
    at finalizeAnalysis (...)

to stderr and exited 0. The SDK's message named none of it. Diagnosing it meant re-running the binary by hand outside the SDK — which is exactly the work the exception exists to save.

Where

Both subprocess backends, same shape:

  • cldk/analysis/typescript/codeanalyzer/codeanalyzer.py:232-236 — the CompletedProcess is not even bound on this path.
  • cldk/analysis/java/codeanalyzer/codeanalyzer.py:290-294console_out is bound and then unused in the message.

The Python backend is unaffected: it calls codeanalyzer-python in process, so there is no captured stream to lose.

The check=True path (:222, :280) is fine — CalledProcessError's str() carries the command and the return code, though not the streams either.

Scope boundary

In scope: carry a bounded tail of the analyzer's stderr (and stdout when stderr is empty) into the raised message, on both subprocess backends.

Out of scope: the upstream defects that produced the case — codeanalyzer-typescript#180 (the crash) and #181 (exit 0 on FATAL). The SDK cannot rely on those being fixed; an analyzer that fails in a new way should still be diagnosable from the exception.

Goals

  • The "did not generate analysis.json" exception includes the captured stderr tail, truncated to a sane bound, for both Java and TypeScript
  • The tail is included when the process exited non-zero as well, so CalledProcessError's bare command line is not the whole story
  • A test that fakes an analyzer exiting 0 with a diagnostic on stderr and no output file, and asserts the diagnostic reaches the raised message

Caveats and known risks

  • The output can be large; a tail bound is required, and it must be applied to bytes actually read, not to a promise about analyzer behaviour.
  • Analyzer output can contain absolute paths from the user's machine. That is already true of every other message the SDK raises, so no new exposure — but do not widen it to full stdout by default.

Definition of done

  • Running either subprocess backend against an analyzer that exits 0 without writing analysis.json yields an exception naming both the missing file and what the analyzer said, and a test pins it.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions