fix(xlsx): external-workbook references fall back to their cached value - #275
fix(xlsx): external-workbook references fall back to their cached value#275JiaZhengOng wants to merge 1 commit into
Conversation
A formula referencing another workbook (=[1]Sheet!A1) can't be resolved without the linked file and surfaces as #REF!, which poisons every dependent total. Excel keeps the cell's last cached <v>; fall through to it when an external ref errors, so SUMs over linked cells compute instead of cascading #REF!. Genuine (non-external) errors still propagate.
|
Thanks for this one — but I'm holding it pending a reproducing file, because I couldn't verify the bug on our engine. I built synthetic cases with external-workbook refs ( Since it doesn't reproduce, I can't tell whether this is fixing a reachable bug or is a no-op on our current code — and the Could you attach a minimal |
|
Thanks! And you've actually put your finger on it — Here's a self-contained repro generator (pure stdlib) — save as
build_repro.pyimport zipfile, os, sys
OUT = sys.argv[1] if len(sys.argv) > 1 else "repro.xlsx"
PARTS = {
"[Content_Types].xml": '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
<Default Extension="xml" ContentType="application/xml"/>
<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>
<Override PartName="/xl/externalLinks/externalLink1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml"/>
</Types>''',
"_rels/.rels": '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
</Relationships>''',
"xl/workbook.xml": '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
<sheets><sheet name="ALL SUMMARY" sheetId="1" r:id="rId1"/></sheets>
<externalReferences><externalReference r:id="rId2"/></externalReferences>
</workbook>''',
"xl/_rels/workbook.xml.rels": '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink" Target="externalLinks/externalLink1.xml"/>
</Relationships>''',
"xl/worksheets/sheet1.xml": '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<sheetData>
<row r="2"><c r="B2"><f>'[1]TALLY JULY'!H100</f><v>100</v></c></row>
<row r="3"><c r="B3"><f>'[1]TALLY JULY'!H200</f><v>200</v></c></row>
<row r="4"><c r="B4"><f>'[1]TALLY JULY'!H300</f><v>300</v></c></row>
<row r="5"><c r="B5"><f>SUM(B2:B4)</f><v>600</v></c></row>
</sheetData>
</worksheet>''',
"xl/externalLinks/externalLink1.xml": '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<externalLink xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
<externalBook r:id="rId1">
<sheetNames><sheetName val="TALLY JULY"/></sheetNames>
<sheetDataSet><sheetData sheetId="0">
<row r="100"><cell r="H100"><v>100</v></cell></row>
<row r="200"><cell r="H200"><v>200</v></cell></row>
<row r="300"><cell r="H300"><v>300</v></cell></row>
</sheetData></sheetDataSet>
</externalBook>
</externalLink>''',
"xl/externalLinks/_rels/externalLink1.xml.rels": '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath" Target="TALLY%20SOURCE.xlsx" TargetMode="External"/>
</Relationships>''',
}
if os.path.exists(OUT): os.remove(OUT)
with zipfile.ZipFile(OUT, "w", zipfile.ZIP_DEFLATED) as z:
for name, data in PARTS.items(): z.writestr(name, data)
print("wrote", OUT)Quoted vs unquoted on main:
One wrinkle that hid it: reading Thanks also for the |
A formula referencing another workbook (=[1]Sheet!A1) can't be resolved without the linked file, so it surfaces as #REF! — which then poisons every total built on it (=SUM(...) over the column → #REF!). Excel keeps each such cell's last cached and computes totals from those, keeping the sheet usable.
This makes ResolveCellResult fall through to the cached value when an external-workbook reference (the [n] marker) evaluates to an error, instead of propagating #REF!. Genuine errors (no external link) still propagate.
Validation: across real workbooks with cross-file links, this turned 107 #REF!-cascade cells into their correct Excel values (spot-checked exact, e.g. =SUM(B19:B21) → 10609273.8). No regression — only external-ref error cells are touched.
Tradeoff (flagging for your call): the cached value can be stale if the linked file changed since last save. This mirrors Excel's own behavior (it shows the last cached external value until you refresh), so it's arguably the more faithful default — but noting it in case you'd rather keep the explicit #REF!.