Skip to content

Fix formula COMException 0x800A03EC by falling back Formula2→Formula - #751

Open
lpittman-g wants to merge 1 commit into
sbroenne:mainfrom
lpittman-g:cursor/fix-formula2-fallback-750
Open

Fix formula COMException 0x800A03EC by falling back Formula2→Formula#751
lpittman-g wants to merge 1 commit into
sbroenne:mainfrom
lpittman-g:cursor/fix-formula2-fallback-750

Conversation

@lpittman-g

Copy link
Copy Markdown

Summary

Test plan

  • On Excel 2019 de-DE: set-values A1:A2, set-formulas A3==A1+A2, get-formulas A1:A3 succeed
  • On Microsoft 365: Formula2 path still used when available (no regression on dynamic-array tables)
  • Values / format / worksheet tools unchanged

Closes #750

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

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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-formulas to read formulas via a new helper that prefers Range.Formula2 and falls back to Range.Formula on 0x800A03EC.
  • Updated range set-formulas to write formulas via a similar helper with the same fallback behavior.
  • Introduced ComUtilities.GetRangeFormulas / SetRangeFormulas plus a named HRESULT constant for 0x800A03EC.
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

  • SetRangeFormulas only 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.

Comment on lines +387 to +390
/// <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>
Comment on lines +404 to +407
catch (COMException ex) when (ex.HResult == ExcelObjectDefinedError)
{
return range.Formula;
}

@lpittman-g lpittman-g left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved

@lpittman-g lpittman-g left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve- All

@lpittman-g lpittman-g left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve

@lpittman-g

Copy link
Copy Markdown
Author

@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.

@sbroenne sbroenne left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 — the changeset-check workflow 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 to Formula2 to 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-formulas and range 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[MCP] ## Bug: range get-formulas / set-formulas always fail with COMException 0x800A03EC (de-DE locale, Excel 2019 32-bit)

3 participants