Skip to content

App tool schemas omit list_threads/read_thread maxima, causing deterministic retries #40232

Open

Description

@KoljaB

Version

Codex Desktop 26.818.41509, bundled command runner 0.149.0-alpha.4.1, Windows.

Problem

The app-hosted tool schemas expose numeric pagination parameters without machine-readable maxima:

  • list_threads.limit?: number
  • read_thread.turnLimit?: number

The descriptions say only "Maximum number..." but do not state the actual limits. The server then rejects:

  • list_threads({limit: 100}): maximum is 50
  • read_thread({turnLimit: 20, ...}): maximum is 10

An agent auditing task history has no schema signal that these otherwise reasonable values are invalid, so it spends a failed tool call and another model turn discovering each hidden contract.

Expected behavior

Publish the server constraints in the generated JSON Schema and prose:

  • list_threads.limit.maximum = 50
  • read_thread.turnLimit.maximum = 10

Include defaults/minima where applicable, and keep host validation and callable schema generated from the same source so they cannot drift.

Why this matters

These are deterministic, preventable failures. Complete schemas let the client/model choose a valid request on the first attempt and avoid retry-token amplification. No private task data or local paths are needed to reproduce.

Activity

  1. added
    bugSomething isn't working
    appIssues related to the Codex desktop app
    app-serverIssues involving app server protocol or interfaces
    tool-callsIssues related to tool calling
    on Aug 23, 2026
  2. ReggieCarey commented on Aug 29, 2026

    @ReggieCarey

    Reproduced independently on macOS with Codex Desktop build 151.0.7922.174: list_threads with limit 100 was rejected by the server maximum of 50, and read_thread with turnLimit 20 was rejected by the server maximum of 10, although neither maximum was exposed in the callable tool description. Both calls succeeded on the first retry at 50 and 10. Suggested regression coverage: assert published schema maxima match server validators, verify boundary values 50 and 10 succeed, and verify 51 and 11 are rejected before MCP execution. No logs or user content are attached.

  3. aidawilliam41-ops commented on Sep 8, 2026

    @aidawilliam41-ops

    Current Windows confirmation: model-visible list_threads limit still omits 50

    On 2026-09-08, with Codex Desktop 26.901.6511.0, the model-visible declaration still exposes limit?: number. Its parameter description says:

    Maximum number of non-pinned thread summaries to return. Pinned threads are always returned in full.

    The description does not state the supported maximum. One bounded read-only boundary check:

    {"limit":51}

    returned:

    list_threads received invalid arguments: limit: Too big: expected number to be <=50.
    

    This confirms the same missing-limit guidance on a newer Windows build. The observation concerns the declaration and description actually shown to the model; I did not inspect the underlying wire JSON Schema in this check, and did not retest read_thread.turnLimit.

    Please include 1–50 directly in the model-visible parameter description and preserve the validator constraints wherever schemas are rendered. This avoids a predictable failed call just to discover an existing limit. No task content or private identifiers are included.

  4. aidawilliam41-ops commented on Sep 14, 2026

    @aidawilliam41-ops

    Additional affected parameter: read_thread.maxOutputCharsPerItem.

    On September 14, 2026, in Codex Desktop on Windows, the model-visible declaration is maxOutputCharsPerItem?: number. Its description says “Maximum characters to keep for each included Codex output or chat message,” without stating the allowed ceiling.

    One bounded, read-only boundary comparison against the same accessible task, with turnLimit: 1 and includeOutputs: false:

    • maxOutputCharsPerItem: 20001 was rejected:
      read_thread received invalid arguments: maxOutputCharsPerItem: Too big: expected number to be <=20000.
    • Changing only that value to 20000 succeeded.

    Please expose the existing 20,000-character maximum in the model-visible parameter description and preserve it wherever the schema is rendered, alongside the pagination bounds already covered by this issue.

    This check establishes the rendered contract and server validation boundary; it does not inspect the underlying wire JSON Schema. No task content or identifiers are included.

  5. aidawilliam41-ops commented on Sep 20, 2026

    @aidawilliam41-ops

    A new occurrence during ordinary work, rather than an intentional boundary probe, on September 20, 2026 (Windows Codex Desktop).

    At 11:44:06 UTC, the agent called:

    {"limit":100}

    The native list_threads tool rejected it with:

    list_threads received invalid arguments: limit: Too big: expected number to be <=50.
    

    At 11:44:10 UTC, it changed the value to 50; that call completed successfully at 11:44:12 UTC. The observed impact was one avoidable failed read-only call and a corrective call. No task data changed.

    Recorded model/settings: GPT-5.6 Sol (gpt-5.6-sol), reasoning effort Ultra. These are the applicable local turn-context settings.

    This adds a spontaneous working-session occurrence to my earlier boundary checks. Separately, the declaration currently exposed to this reporting task still says limit?: number and describes the number of non-pinned summaries, without stating the ceiling of 50. The installed package read at reporting time is 26.915.4065.0; the exact package at the earlier failed call was not separately captured. I did not recover the historical tool schema or inspect the wire JSON Schema.

    Please expose the supported ceiling directly in the model-visible parameter description. No private task content or identifiers are included.

  6. sharifhsn commented on Oct 3, 2026

    @sharifhsn

    Adding a reproducible public-source explanation for missing bounds, beyond another boundary probe.

    At current public commit 6326163b9abd7802c0e57be4e326e5f898bbba75, codex_tools silently loses numeric bounds, string-length bounds, and maxItems while parsing tool schemas. The loss occurs even with compaction disabled.

    The desktop-style TUI tool definitions already supply minimum/maximum for list/read limits and minLength for identifiers. Dynamic tool parsing passes input schemas through parse_tool_input_schema.

    Both parser entry points eventually deserialize into the typed JsonSchema representation. That type has minItems, but has no fields for minimum, maximum, minLength, maxLength, or maxItems; Serde ignores the unrepresented fields.

    I compiled a standalone Rust fixture using verbatim copies of the four upstream schema modules and their dependencies (serde, serde_json, jsonptr, urlencoding). The input was:

    {
      "type":"object",
      "properties":{
        "limit":{"type":"integer","minimum":1,"maximum":50},
        "cursor":{"type":"string","minLength":1,"maxLength":1000},
        "targets":{"type":"array","minItems":1,"maxItems":8,"items":{"type":"string"}}
      },
      "additionalProperties":false
    }

    Serializing the result of either parse_tool_input_schema(&input) or parse_tool_input_schema_without_compaction(&input) yielded:

    {
      "additionalProperties":false,
      "properties":{
        "cursor":{"type":"string"},
        "limit":{"type":"integer"},
        "targets":{"items":{"type":"string"},"minItems":1,"type":"array"}
      },
      "type":"object"
    }

    Assertions confirmed all five tested constraint keywords were absent and minItems:1 survived. The schema is small, so this is not explained by the 5,000-byte compaction budget.

    On macOS Desktop 26.930.21537/build 12776, bundled backend 0.159.0-alpha.12.1, bounded live controls also confirmed:

    • list_threads.limit:51 rejects; 50 succeeds.
    • read_thread.turnLimit:11 rejects; 10 succeeds.
    • read_thread.maxOutputCharsPerItem:20001 rejects; 20000 succeeds.
    • read_thread.cursor:"" rejects; omitting the cursor succeeds.

    The model-facing declarations do not state these bounds. I did not capture the proprietary desktop wire schema, so I cannot prove its exact rendering path uses this public parser. The public parser's information loss itself is independently reproduced.

    Suggested coverage: round-trip bounded schemas through both parser entry points, assert relevant bounds remain available to the model, and test their agreement with runtime validators. Preserve machine-readable constraints where the selected model/API supports them; render unsupported bounds as clear parameter descriptions rather than silently discarding them. This also avoids treating a larger schema-size budget as the fix.

  7. stream727 commented on Oct 8, 2026

    @stream727

    追加で read_thread.maxOutputCharsPerItem にも、モデルに見える宣言とサーバー検証の上限の不一致を確認しました。重複Issueは作りません。

    2026-10-09、macOS 26.3 / Apple Silicon、Codex 26.1002.52244(build 13536)の履歴監査中、maxOutputCharsPerItem: 40000 を指定した要求が、次の実際のエラーで拒否されました:

    read_thread received invalid arguments: maxOutputCharsPerItem: Too big: expected number to be <=20000.
    

    20000 へ修正した要求は受理され、その後のページ取得に使えました。一方、モデルに提供された引数の説明は以下で、上限の記載がありませんでした:

    // Maximum characters to keep for each included Codex output or chat message.
    maxOutputCharsPerItem?: number;

    生のMCPサーバーJSON Schemaを別途取り出して確認したわけではなく、ここで指摘するのはモデルが実際に見た宣言と検証結果の差です。既報の limit と turnLimit に加え、このフィールドにも maximum: 20000 と説明文中の上限を反映し、サーバー検証とモデル向け宣言を同じ定義から生成してほしいです。

    添付は不要な入力制約の問題なので、会話内容・対象ID・生ログは公開していません。

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

    appIssues related to the Codex desktop appapp-serverIssues involving app server protocol or interfacesbugSomething isn't workingtool-callsIssues related to tool calling

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions