Skip to content

make_adapters surfaces an out-of-tree adapter's signature mismatch as a bare traceback, after the run dir exists #569

Description

@pbean

Found while triaging a codex finding on PR #568. The compatibility half of that finding does not apply (see below); this is the half that outlives it.

The gap

runsetup.make_adapters builds every adapter class with:

by_cfg[key] = cls(**build_kwargs)
except builder.construct_error as e:
    raise SystemExit(f"error: {e}") from e

construct_error is family-declared and covers what a family says its __init__ can raise — () for generic, (OpencodeServerError,) for opencode. A signature mismatch is not that: an out-of-tree class whose __init__ does not accept a keyword core passes raises TypeError, which no family declares, so it escapes.

Two lines up, the kind.load() arm already states why that matters:

By here compose_run has already written the run state and pid, so an escaping ImportError strands a run directory behind a traceback.

The same is true here, and one step later. The ImportError arm was given a clean error: line naming the profile and the kind; the construct call has no equivalent for the mismatch case.

Why it is not urgent

The out-of-tree adapter-class capability (#226, PR #239) has not shipped in a tagged release — the last tag is v0.9.1 and the entry is under ## [Unreleased]. The authoring guide states there is no out-of-tree adapter-class package to copy yet, so today the only classes reaching this line are the bundled ones, which are edited in the same commit as any new keyword.

PR #568 documents the obligation on the author side (accept **kwargs; the bootstrap keyword set grows), which is the cheap half and the one that belongs before first release. This issue is the core-side half: even a correct contract gets violated, and the failure should read like the rest of the bootstrap rather than like a crash.

Shape

Catch TypeError around the construct call and re-raise as SystemExit naming the profile, the kind, and the offending keyword — matching the ImportError arm above it. TypeError only, on the same rule that arm states: a declared failure gets a clean line, anything else is a bug in that package and must surface as itself.

Care needed on one point: a TypeError raised from inside a working __init__ is a bug in that package and must not be relabelled as a signature mismatch. Distinguishing the two means inspecting the exception rather than merely its type — worth pinning with a test that a TypeError thrown from the constructor body still surfaces as itself.

Related: #226, PR #239, PR #568.

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

    P3Robustness, enhancement, tests, or docs worth schedulingarea:adaptersCoding-CLI adapters and profilesbugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions