TypeScript SDK: invalid input leaks the temporary output-schema file
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 72/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- javascript, node.js, typescript
- Domain
- cli
Research direction
The leak is in sdk/typescript/src/thread.ts, in Thread.runStreamedInternal(), where createOutputSchemaFile runs before normalizeInput and before the cleanup try/finally. Read that ordering first, then reproduce with the JavaScript snippet using null input and check for leftover codex-output-schema-* directories. Done means invalid input rejects with no temporary schema directory left behind, and tests/outputSchemaCleanup.test.ts passes; the issue's candidate validates input before allocating the resource.
Written by the indexing model from the issue text.
Description
What issue are you seeing?
The TypeScript SDK creates the temporary output-schema file before validating input, then enters its cleanup try/finally only after input normalization. If a JavaScript caller supplies invalid input such as null, normalization throws and leaves a codex-output-schema-* directory containing schema.json behind.
This is a low-severity cleanup defect for invalid JavaScript input. Rejecting null is expected; TypeScript callers respecting the static input type do not trigger this case.
What steps can reproduce the bug?
Confirmed with SDK source at 0b021a5fc981448a2555bd378518e85e3aae3016, Node v26.12.1, macOS. Build/install the SDK from that revision and run this JavaScript as an ES module where @openai/codex-sdk resolves to that build. No model call is needed: input normalization fails before execution.
import assert from 'node:assert/strict';
import { Codex } from '@openai/codex-sdk';
import { readdir, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
const root = tmpdir();
const before = new Set(await readdir(root));
let leaked = [];
try {
await assert.rejects(
new Codex().startThread().run(null, { outputSchema: { type: 'object' } }),
TypeError,
);
leaked = (await readdir(root)).filter(
name => name.startsWith('codex-output-schema-') && !before.has(name),
);
console.log('temporary schema directories left behind:', leaked.length);
for (const name of leaked) {
console.log('contents:', await readdir(join(root, name)));
}
} finally {
for (const name of leaked) {
await rm(join(root, name), { recursive: true, force: true });
}
}
Use a disposable environment without other SDK runs so temporary-directory comparisons are unambiguous. Our original harness used the actual source modules with a controlled executor and observed one leaked directory containing only schema.json. A valid-input control with the same schema left no directory.
What is the expected behavior?
Invalid input should reject without retaining the temporary schema file or directory.
Additional information
Root cause: Thread.runStreamedInternal() awaits createOutputSchemaFile, then calls normalizeInput, before entering the cleanup guard. The helper's own write-error cleanup cannot cover this later exception.
A local candidate validates input before allocating the temporary resource. Checks against that fix, based on a09812981de7, reported:
13 control: valid input with schema -> run ok, schema dir cleaned
13 after: invalid input rejected with TypeError, schema directories left behind=0
The regression suite tests/outputSchemaCleanup.test.ts fails against the old source and passes against the candidate. It spies on os.tmpdir() to isolate the test directory; setting Jest's sandboxed process.env.TMPDIR alone does not redirect the native os.tmpdir() result. Checks ran in an isolated no-network container. Full native CLI integration tests were not run. The candidate fix remains local.
Searched existing issues for SDK output-schema cleanup, temporary schema files, and schema leaks before filing. Prepared with Codex assistance as an issue-based contribution.
- Dominant language
- Rust
- Stars
- 133k
- Forks
- 21.1k
- Avg merge
- 1m
- Merged PRs (30d)
- 995
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from openai/codex
-
bug CLI
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
openai/codex#60494 · 1 comment ·
Maintainers usually reply within 1 day
-
app bug pets
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
Maintainers usually reply within 1 day
-
bug skills
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 1 day
-
bug config hooks
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
openai/codex#60103 · 1 comment ·
Maintainers usually reply within 1 day
-
app bug windows-os
Difficulty 2/5 1-3 hours Newbie friendliness 67/100
Maintainers usually reply within 1 day
Similar issues
-
Panic on live viewport resize when unstyled elements exist in display: none subtreePossibly taken @GoCoder7 claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
DioxusLabs/blitz#1488 ·
Maintainers usually reply within 1 day
-
🏷️ good first issue enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
Maintainers usually reply within 1 day
-
S-Needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
vectordotdev/vrl#2042 ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
Maintainers usually reply within 1 day