Bug - Codex VS Code Ext - prompts are not queued or load forever - with solution

Well last night I was literally forking each chat after each finished task or was restarting VS Code so i could send the next prompt.

The reason is that there is a undefined json error (as shown in the logs)

What I did today was telling codex to do this in a new instance of vs code so it could change the javascript of codex itself without destroying its own session:

Investigate and fix the unhandled `undefined` JSON response in the Codex VS Code extension.

The issue is visible in logs as something like:

Failed to release queued message send lock
errorMessage="\"undefined\" is not valid JSON"
errorName=SyntaxError
errorStack="SyntaxError: \"undefined\" is not valid JSON
    at JSON.parse (<anonymous>)
    at e.onFetchResponse (.../webview/assets/app-initial-*.js:...)
    ..."

The goal is NOT to change queue semantics, retry turns, or work around unrelated thread behavior.

The goal is only to identify why a response reaches `JSON.parse()` as `undefined`, then fix that response boundary safely and minimally.

Use the following investigation approach.

1. Locate the installed extension

On Linux it is typically under:

    ~/.vscode/extensions/

Find the Codex extension:

    find ~/.vscode/extensions -maxdepth 1 -type d -iname 'openai.chatgpt-*'

Enter the installed extension directory:

    cd ~/.vscode/extensions/openai.chatgpt-<version>-linux-x64

2. Inspect the extension structure

Check the manifest:

    cat package.json

The main VS Code extension entry point should look similar to:

    "main": "./out/extension.js"

List the webview assets:

    find webview -type f | sort | head -100

Inspect the webview entry point:

    cat webview/index.html

List the larger application bundles:

    ls -lh webview/assets/app-initial-*.js

3. Locate the relevant queue/IPC code

Search the extension host bundle:

    grep -oE \
    'queued-followups|queued-follow-ups|thread-queued-followups-changed|thread-stream-state-changed|thread-follower-set-queued-follow-ups-state|thread-follower-remove-queued-message|thread-follower-clear-queued-messages' \
    out/extension.js | sort | uniq -c

Find the corresponding webview bundles:

    grep -RIl \
      -E 'thread-follower-set-queued-follow-ups-state|thread-follower-remove-queued-message|thread-follower-clear-queued-messages|thread-queued-followups-changed' \
      webview/assets

Also locate the setting-related bundle if useful:

    grep -RIl 'followUpQueueMode' \
      webview/assets/app-initial-*.js \
      webview/assets/general-settings-*.js \
      webview/assets/user-message-*.js

4. Locate the failing response parser

Search all app bundles for the response handler:

    grep -RIl 'onFetchResponse' webview/assets/app-initial-*.js

Then extract context without pretty-printing the entire minified bundle:

    python3 - <<'PY'
    from pathlib import Path

    for p in Path("webview/assets").glob("app-initial-*.js"):
        s = p.read_text(errors="replace")

        for term in [
            "onFetchResponse",
            "Failed to release queued message send lock",
            "JSON.parse",
        ]:
            pos = 0
            while True:
                i = s.find(term, pos)
                if i < 0:
                    break

                print("\n" + "#" * 100)
                print(p)
                print(term, "@", i)
                print("#" * 100)
                print(s[max(0, i - 2500):i + 5000])

                pos = i + len(term)
    PY

If the stack trace contains an exact minified line/column, extract that area directly.

For example, for line 3 column 1518:

    python3 - <<'PY'
    from pathlib import Path

    p = Path("webview/assets/app-initial-48c569ae16a4.js")
    lines = p.read_text(errors="replace").splitlines()

    line_number = 3
    column = 1518

    line = lines[line_number - 1]
    print(line[max(0, column - 1200):column + 1800])
    PY

5. Trace the producer and consumer

Do not only patch `JSON.parse()` blindly.

Determine the full response path:

    queued-message lock release
        -> request
        -> VS Code/webview bridge
        -> request handler
        -> handler return value
        -> serialization
        -> response delivery
        -> onFetchResponse
        -> JSON.parse

Specifically determine:

- whether the response value is JavaScript `undefined`
- whether it is the literal string `"undefined"`
- whether the handler intentionally returns no value
- whether `JSON.stringify(undefined)` is involved
- whether an empty/void response is valid for this request
- whether another layer expects a specific JSON response shape

Search for useful related strings:

    grep -Rni \
      -E 'onFetchResponse|queued message send lock|JSON.stringify|JSON.parse|fetch-response|fetchResponse' \
      webview/assets out \
      2>/dev/null

6. Fix the narrowest correct boundary

Preferred fix if the producer is serializing a void result:

Instead of:

    JSON.stringify(result)

normalize only the void response:

    JSON.stringify(result ?? null)

because:

    JSON.stringify(undefined) === undefined
    JSON.stringify(null) === "null"

If an empty response is explicitly valid and the producer cannot safely be changed, make the specific response parser tolerate only empty/void responses.

Conceptually:

    const parsed =
        value === undefined ||
        value === null ||
        value === "" ||
        value === "undefined"
            ? null
            : JSON.parse(value);

Do NOT globally replace or wrap every `JSON.parse()` call.

Do NOT return an invented payload such as:

    { "success": true }

unless the existing protocol clearly specifies that schema.

Do NOT add retries unless investigation proves that the response is temporarily unavailable and a later retry returns valid data.

If the handler deliberately returns void, retrying it will simply return `undefined` again.

7. Back up the bundle before modifying it

For example:

    cp \
      webview/assets/app-initial-48c569ae16a4.js \
      webview/assets/app-initial-48c569ae16a4.js.bak

If another bundle is modified, back that one up separately as well.

8. Keep the patch minimal

The bundles are minified, so avoid reformatting or rewriting the entire file.

Prefer an exact replacement with a script that first verifies that the target fragment occurs exactly once.

Example workflow:

    python3 - <<'PY'
    from pathlib import Path

    p = Path("webview/assets/app-initial-48c569ae16a4.js")
    s = p.read_text()

    old = 'EXACT_ORIGINAL_FRAGMENT'
    new = 'EXACT_PATCHED_FRAGMENT'

    count = s.count(old)
    print("matches:", count)

    if count != 1:
        raise SystemExit("Refusing to patch: expected exactly one match")

    p.write_text(s.replace(old, new, 1))
    PY

9. Validate the modified bundle

If possible:

    node --check webview/assets/app-initial-48c569ae16a4.js

Compare against the backup:

    cmp \
      webview/assets/app-initial-48c569ae16a4.js.bak \
      webview/assets/app-initial-48c569ae16a4.js

For a minified single-line file, inspect only the modified region rather than producing a huge full-file diff.

10. Reload VS Code and reproduce

Use:

    Developer: Reload Window

Then reproduce the operation that previously caused:

    Failed to release queued message send lock
    "undefined" is not valid JSON

Check the latest Codex extension logs:

    grep -Rni \
      -E 'Failed to release queued message send lock|undefined.*valid JSON' \
      ~/.config/Code/logs \
      2>/dev/null | tail -100

The fix is successful if the invalid JSON exception no longer occurs and the relevant operation still completes normally.

11. Report the actual root cause

Document:

- extension version
- affected bundle
- affected function
- exact producer of the `undefined` response
- exact consumer that called `JSON.parse`
- whether the value was JS `undefined` or the string `"undefined"`
- whether the handler intentionally returned void
- the minimal patch
- why `null` is the correct representation, if applicable
- verification steps
- confirmation that no broad JSON parsing behavior was changed

A concise root-cause description should look roughly like this:

"The VS Code webview response bridge unconditionally attempted to JSON.parse a response from a handler that can legitimately return no value. A void JavaScript result was therefore propagated as `undefined`, which is not valid JSON. Normalizing void responses to JSON `null` at the serialization boundary (or explicitly accepting an empty response in this one consumer) prevents the SyntaxError without changing unrelated queue or thread behavior."

Do not investigate or modify unrelated duplicate-turn, replay, model-selection, or queue-ordering behavior as part of this fix.

codex needed roughly 15 minutes to monkey patch it - (it runs on my machine)

I have also reported it to github in hope that it will not be overriden by the next update with the bug still in the code.

So this post is firstly meant as a tip for the guys who have the same problem (you are not helpless - you can fix codex yourself sometimes - let it analyse the problem itself)

And of course secondly just in case someone at OpenAI - if you see this. Please add the fix to the next update.

It was a horrible night!

version 26.5928.31416 and the pre release both have that error

Linux 6.8.0-142-generic x86_64 x86_64

It was also having the error after restart - reload of the extension or the window and after changing the model from 6.1-sol to gpt-6-sol

Thanks for documenting this so clearly.

Your post made me look more closely at another related area: how Codex persists and grows session history over time. My local Codex session storage has now exceeded 60 GB, and that pushed me to start investigating where the growth really comes from — repeated history, compaction snapshots, tool outputs, subagent inheritance, and other forms of storage amplification.

I’m currently exploring a more efficient session-storage architecture that could preserve resume/history capabilities while reducing unnecessary duplication and long-term disk growth.

I’m still validating the idea, but I’ll try to publish a technical proposal soon.

same me :<<<<< I hope this issue will be fixed soon.

bless you @jochenschultz

:saluting_face:

I downgraded the release to the one from 2 days ago, seems to work too if you’re driving astra.

@ OAI: how do we feel about not doing friday night build releases? That would be amazez. Mkaythx. :slight_smile:

It kind of got fixed with the last update - but not as good as codex did it haha…

now sometimes it doesn’t accept the prompt and you have to send it again… which with arrow up to get the last message back and enter is rather inconvenient than an important bug.. but still it is a little annoying…

Give me access to the code! I’ll fix that for free!

Now when sending a message the text will stay in the text box sometimes and when I deleted it the task stopped .. very strange