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.

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