openai / openai/codex

Spreadsheet importer returns shared-string index for an empty XLSX shared string

Open
#38,118 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app bug
Dominant language
Rust
Stars
125k
Forks
19.5k
PR merge metrics
PR metrics pending

Description

What issue are you seeing?

SpreadsheetFile.importXlsx in the Codex Spreadsheets runtime resolves an XLSX shared-string cell incorrectly when the referenced shared string is empty.

For this valid OOXML:

<!-- xl/worksheets/sheet1.xml -->
<c r="A2" t="s"><v>1</v></c>
<c r="B2" t="s"><v>0</v></c>

<!-- xl/sharedStrings.xml -->
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
     count="2" uniqueCount="2">
  <si><t>visible</t></si>
  <si><t/></si>
</sst>

A2 references shared-string index 1, whose resolved content is an empty string. Codex instead returns the raw index text "1". B2 correctly resolves index 0 to "visible".

This can silently turn blank spreadsheet cells into valid-looking numeric strings. Downstream data transformations can therefore write incorrect values without any parse error.

What steps can reproduce the bug?

Environment:

  • Codex App: 26.803.61601 (build 6396)
  • Workspace dependencies bundle: 26.805.11740
  • @oai/artifact-tool: 2.8.39
  • Platform: Darwin 25.5.0 arm64 arm
  1. Decode the sanitized workbook included below.
  2. Import it with the bundled runtime:
import { FileBlob, SpreadsheetFile } from "@oai/artifact-tool";

const workbook = await SpreadsheetFile.importXlsx(
  await FileBlob.load("codex-empty-shared-string-repro.xlsx"),
);

const result = await workbook.inspect({
  kind: "table",
  sheetId: "Repro",
  range: "A1:B2",
  include: "values,formulas",
});

console.log(result.ndjson);
  1. Observe the imported values:
[["empty_shared_string","control"],["1","visible"]]
  1. Open the same workbook in WPS/Excel-compatible software, or export it with LibreOffice Calc:
empty_shared_string,control
,visible

The independent reader correctly leaves A2 blank.

What is the expected behavior?

A2 should resolve to an empty string (or the importer's documented blank-cell representation), never to the shared-string table index.

Expected values:

[["empty_shared_string","control"],["","visible"]]
Additional information
  • The workbook is fully synthetic and contains no user, repository, company, or business data.
  • The XLSX ZIP package passes integrity validation and contains only eight standard OOXML entries.
  • There are no formulas or external links.
  • A structurally identical real-world workbook used a different shared-string index and showed the same failure mode.
  • The behavior is consistent with a falsy empty-string resolution falling back to the raw index. This is an inference from the observed boundary, not a source-code-confirmed root cause.
Sanitized minimal XLSX (base64, 3.6 KB)

SHA-256: aa567082dafc74bd1f2c4ab1d124a9917101a66c4777b572c8645a075e287524

Save the block as repro.b64, then decode it:

python3 -c 'import base64,pathlib; pathlib.Path("codex-empty-shared-string-repro.xlsx").write_bytes(base64.b64decode(pathlib.Path("repro.b64").read_text()))'
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
LQwAAAAA

Contributor guide

Open the contributing guide

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.

Research direction

Start with the supplied minimal XLSX and the SpreadsheetFile.importXlsx call, then inspect the table output for A1:B2. Verify how an empty entry in xl/sharedStrings.xml is resolved when referenced by xl/worksheets/sheet1.xml. Done means the imported values are [["empty_shared_string","control"],["","visible"]] rather than returning the raw index "1".

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, xml
Domain
data
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.