Skip to content

Codex provider fails on nullable anyOf output schemas #146

Description

@grantjayy

Summary

clawpatch ci --provider codex fails against Codex CLI / OpenAI-compatible Responses strict structured output when the provider schema contains nullable fields emitted as anyOf.

The failure occurs before model reasoning. Codex CLI rejects the generated schema:

invalid_json_schema
strict json_schema type must be a string or a non-empty array of strings
param: text.format.schema.properties.findings.items.properties.evidence.items.properties.endLine.type

Environment

  • clawpatch: 0.7.0 (latest npm at time of report)
  • Codex CLI: 0.142.3
  • provider: codex
  • model: gpt-5.5
  • route: OpenAI-compatible Responses API via codex-pooler
  • OS observed: macOS

Minimal reproduction

rm -rf /tmp/clawpatch-pooler-smoke
mkdir -p /tmp/clawpatch-pooler-smoke
cd /tmp/clawpatch-pooler-smoke

git init -q
git config user.email smoke@example.com
git config user.name 'Smoke Test'

cat > sample.py <<'PY'
def add(a, b):
    return a + b
PY

git add sample.py
git commit -q -m init

cat > sample.py <<'PY'
def add(a, b):
    return a + b

def subtract(a, b):
    return a - b
PY

clawpatch ci \
  --since HEAD \
  --include-dirty \
  --provider codex \
  --model gpt-5.5 \
  --reasoning-effort xhigh \
  --jobs 1 \
  --output clawpatch-codex.md

Observed result:

clawpatch review feature-error ... error=codex provider failed: OpenAI Codex v0.142.3
...
ERROR: {"error":{"code":"invalid_json_schema","message":"strict json_schema type must be a string or a non-empty array of strings","param":"text.format.schema.properties.findings.items.properties.evidence.items.properties.endLine.type","type":"invalid_request_error"},"status":400,"type":"error"}

Root cause

dist/provider-schema.js currently generates provider schemas via:

z.toJSONSchema(schema, { io: "input", unrepresentable: "any" })

For nullable fields like evidenceLineSchema:

const evidenceLineSchema = z.number().int().min(0).nullable();

Clawpatch emits JSON Schema like:

{
  "anyOf": [
    { "type": "integer" },
    { "type": "null" }
  ]
}

That is valid generic JSON Schema, but Codex CLI's --output-schema / Responses strict schema path does not accept it. I isolated the compatibility issue with direct Codex CLI probes:

  • schema using anyOf: [{"type":"integer"},{"type":"null"}] fails with the same ...endLine.type error.
  • equivalent schema using "type": ["integer", "null"] succeeds.

Locally validated fix

I patched the installed package locally to normalize the exact nullable anyOf pattern into a strict-compatible type array before handing the schema to Codex.

Conceptual patch:

function normalizeNullableAnyOf(schema) {
  const anyOf = schema["anyOf"];
  if (!Array.isArray(anyOf) || anyOf.length !== 2) return;

  const nullIndex = anyOf.findIndex(
    (item) => isRecord(item) && item["type"] === "null" && Object.keys(item).length === 1,
  );
  if (nullIndex === -1) return;

  const other = anyOf[nullIndex === 0 ? 1 : 0];
  if (!isRecord(other) || typeof other["type"] !== "string") return;

  delete schema["anyOf"];
  for (const [key, item] of Object.entries(other)) {
    schema[key] = item;
  }
  schema["type"] = [other["type"], "null"];
}

Called from stripProviderUnsupportedSchemaKeywords() after recursively stripping nested schema fields.

After applying that local normalization, the same real Codex-path smoke test passed:

clawpatch review feature-done ... findings=0
clawpatch review done ... reviewed=1 findings=0
EXIT_CODE=0

Expected behavior

clawpatch ci --provider codex should emit a Codex/Responses-compatible strict schema for nullable fields, or otherwise avoid using nullable anyOf in the Codex provider schema path.

Notes

This may also be valid to fix in Codex CLI by accepting/normalizing nullable anyOf, but Clawpatch can make its Codex provider path robust today by normalizing this common nullable shape itself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Urgent regression or broken agent/channel workflow affecting real users now.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:auth-providerThis issue is about auth, provider routing, model choice, or SecretRef resolution.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    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