Fix formula COMException 0x800A03EC by falling back Formula2→Formula - #751
Fix formula COMException 0x800A03EC by falling back Formula2→Formula#751lpittman-g wants to merge 1 commit into
Conversation
Prefer Range.Formula2 but fall back to Range.Formula when Formula2 throws 0x800A03EC, which breaks get-formulas/set-formulas on Excel 2019 32-bit (including de-DE) while values and VBA still work. Fixes sbroenne#750
There was a problem hiding this comment.
🟡 Not ready to approve
The new fallback helpers include misleading HRESULT documentation and don’t yet handle the “Formula2 member missing” case implied by the repo’s Excel 2016+ support claim, leaving compatibility gaps unresolved.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
This PR addresses Excel COM compatibility for formula read/write operations by adding a Formula2 → Formula fallback to avoid COMException 0x800A03EC on Excel 2019 (notably some locales / 32-bit), while keeping Formula2 as the preferred path for dynamic-array semantics.
Changes:
- Updated
range get-formulasto read formulas via a new helper that prefersRange.Formula2and falls back toRange.Formulaon0x800A03EC. - Updated
range set-formulasto write formulas via a similar helper with the same fallback behavior. - Introduced
ComUtilities.GetRangeFormulas/SetRangeFormulasplus a named HRESULT constant for0x800A03EC.
File summaries
| File | Description |
|---|---|
| src/ExcelMcp.Core/Commands/Range/RangeCommands.Formulas.cs | Switches formula get/set to use ComUtilities helpers for Formula2→Formula fallback. |
| src/ExcelMcp.ComInterop/ComUtilities.cs | Adds reusable helpers/constants to implement the fallback behavior for formula reads/writes. |
Review details
Suppressed comments (1)
src/ExcelMcp.ComInterop/ComUtilities.cs:422
SetRangeFormulasonly falls back on 0x800A03EC. If Formula2 is missing on a supported Excel install (Excel 2016 per README), set-formulas would still fail; consider adding the same “member not found/unknown name” fallback handling here once the exact HRESULT/exception is confirmed.
catch (COMException ex) when (ex.HResult == ExcelObjectDefinedError)
{
range.Formula = formulas;
}
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
| /// <summary> | ||
| /// HRESULT for Excel "application-defined or object-defined error". | ||
| /// Common when Formula2 is unavailable (Excel 2019 / some locales) or the call is rejected. | ||
| /// </summary> |
| catch (COMException ex) when (ex.HResult == ExcelObjectDefinedError) | ||
| { | ||
| return range.Formula; | ||
| } |
|
@copilot Fix the code for all comments in this review thread. When a review comment includes a suggested change, apply the suggestion exactly. Do not make changes beyond what is described in the linked review thread. |
There was a problem hiding this comment.
Thanks for this @lpittman-g — and nice diagnosis. I confirmed the root cause against Microsoft''s docs: Range.Formula2 is a Dynamic Arrays–era API, and Excel 2016/2019 (perpetual, no Dynamic Arrays) genuinely can''t service it, so it throws the generic 0x800A03EC while legacy Range.Formula keeps working — exactly what the reporter saw. Since we advertise "Excel 2016+" support, falling back is the right call, not a won''t-fix.
A few changes are needed before this can merge:
1. Detect the capability once per session instead of try/catching every call
Right now every get/set-formulas call on an affected Excel throws + catches a COMException. Please cache the verdict on the session — e.g. an ExcelCapabilities holder on ExcelContext (alongside FormatTranslator), since _context is created once per batch and reused across every Execute. Probe once, then route directly thereafter.
2. Determine capability with a read probe, not the write
0x800A03EC is Excel''s generic "application/object-defined error" — it''s also thrown for genuinely invalid formulas, protected sheets, etc. Catching it on the write path (Formula2 =) can silently swallow a real error and retry via legacy Formula. Reading Formula2 is side-effect-free and can''t be confused with an invalid-formula error, so please probe capability with a read and let write failures propagate cleanly.
3. Required by our contribution gates
- Add a changeset (
npx changeset) referencing #750 — thechangeset-checkworkflow will fail the PR without one. - Add a CHANGELOG/docs note that on non–Dynamic-Arrays Excel (2016/2019), formulas fall back to legacy
Range.Formula, which reintroduces the@implicit-intersection behavior inside Tables — the exact thing we switched toFormula2to avoid (see the existing CHANGELOG entry for that change). Users on 2019 deserve to know the trade-off.
4. Same-pattern check — verified clean, just needs a note
I checked the other Formula2 call sites so you don''t have to: the only other Range.Formula2 writer is PythonInExcelCommands, which is Microsoft 365–only (always has Dynamic Arrays) → unaffected. The other matches — Validation.Formula2 (data-validation second bound) and FormatCondition.Formula2 (conditional-format second formula) — are different COM properties present on all Excel versions and unrelated to Dynamic Arrays. So no other call sites need changes; a one-line note to that effect in the PR description covers our bug-fix same-pattern requirement.
On testing
I recognize the fallback branch is genuinely hard to cover — we can''t force 0x800A03EC on a Dynamic-Arrays-capable CI/dev Excel, and our policy is integration-only (no COM mocking). Two things instead:
- Please validate on your own machine (Excel 2019 32-bit, de-DE) and paste the before/after for both
range set-formulasandrange get-formulas— that''s the exact path our CI can''t reach, and you have the ideal repro environment. - Confirm the existing round-trip formula regression tests (the Table
@-injection ones) still pass on a Dynamic-Arrays Excel.
Happy to help with the ExcelCapabilities piece if useful.
Summary
range get-formulas/set-formulasusedRange.Formula2only.Formula2throwsCOMException 0x800A03ECeven thoughRange.Formulaworks (see [MCP] ## Bug:range get-formulas/set-formulasalways fail with COMException 0x800A03EC (de-DE locale, Excel 2019 32-bit) #750).ComUtilities.GetRangeFormulas/SetRangeFormulasthat tryFormula2then fall back toFormula.Test plan
set-valuesA1:A2,set-formulasA3==A1+A2,get-formulasA1:A3 succeedCloses #750