TypeScript SDK: invalid input leaks the temporary output-schema file

Open Beginner friendly
#60,299 0 comments 0 reactions 0 assignees View on GitHub

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

bug
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

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from openai/codex

All issues in openai/codex

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.