How to Debug Python in Excel

Excel
Python
Debugging
Troubleshooting
A boundary-first method for diagnosing workbook bindings, Python logic, published outputs, packages, and save/reopen failures.
Published

August 25, 2026

The fastest way to debug Python in Excel is to identify which boundary failed before changing code.

A Python-powered workbook spans several systems at once: worksheet values, workbook bindings, Python logic, package/runtime behavior, published outputs, Excel formulas, saved notebook state, and sometimes external services. A visible symptom can originate several layers away.

Use one sequence repeatedly:

Observe the symptom → identify the boundary → inspect the smallest state on each side → reproduce → fix → verify after reopen.

This article focuses on Boardflare Python for Excel and works through three common failure patterns. The maintained Troubleshooting and Reference page remains the source of truth for current error states and API details.

Start with the symptom, not the code

Use the visible failure to choose the first boundary to inspect.

Symptom First boundary to inspect
Notebook value does not change after editing Excel Worksheet → bf.inputs() binding
Python result is numerically wrong Validated input → model logic
Notebook looks correct but worksheet output is wrong bf.publish() → BF.OUTPUT()
BF.FUNCTION() does not resolve Published function → worksheet call
Import fails Browser/WebAssembly package compatibility
Workbook works until closed Session state → saved workbook state
Workbook opens with #BUSY! indefinitely Runtime startup → publication registry

Do not start by rewriting the model. First prove where correct state stops flowing.

Failure 1: Excel changed, but Python did not

Suppose a planner edits Inputs!A4:D20, but the notebook output does not change.

Start at the worksheet-to-Python boundary:

inputs = bf.inputs(
    data=bf.ref("Inputs!A4:D20", headers=True),
    threshold="Dashboard!B6",
)

inputs
inputs.errors
inputs["data"]
inputs["threshold"]

Check four things in order:

  1. The worksheet value. Is the user editing the range the notebook actually references?
  2. The input widget. Does the displayed binding show the expected canonical reference and shape?
  3. inputs.errors. Did the host reject or fail to materialize the binding?
  4. The Python value. Does inputs["data"] or inputs["threshold"] contain the changed state?

If the Python value is already wrong, do not debug downstream calculations yet.

A useful deliberate failure is to change the worksheet layout without updating the reference. If the binding now points at the wrong columns or headers, the notebook should expose that at the input boundary rather than letting you chase a later chart or solver error.

Once the value arrives correctly, validate it immediately:

if data.empty:
    raise ValueError("Input table contains no rows.")

if data["Amount"].isna().any():
    raise ValueError("Amount contains blank values.")

if not 0 <= threshold <= 1:
    raise ValueError("Threshold must be between 0% and 100%.")

Validation moves failures toward their cause. A blank workbook cell that silently becomes NaN is much harder to diagnose if it travels through several transformations before failing inside a solver or chart.

See Working with Excel for current input-reference behavior and type conversion.

Failure 2: Python is right, but Excel says the output is unavailable

A notebook can calculate the correct DataFrame while Excel still receives the wrong output.

Treat publication as an interface of its own:

publication = bf.publish(outputs={
    "summary": summary,
    "detail": detail,
})
publication

Now suppose the worksheet still contains:

=BF.OUTPUT("details")

The model is not the problem. The interface is.

Check:

  • whether the expected output name is present in the current bf.publish(...) mapping;
  • spelling and case in the worksheet formula;
  • whether a refactor renamed the Python output without updating Excel;
  • whether the published value can be converted to the intended worksheet shape;
  • whether publication actually completed successfully.

When the publication object is assigned to a variable, publication.consumers can also help identify live worksheet formulas connected to the current registry.

This failure is worth reproducing deliberately during development: rename one published key, confirm the corresponding worksheet formula fails, then restore the contract. That proves you know how a publication failure differs from a calculation failure.

The same principle applies to BF.FUNCTION(). Verify the published function name and signature before changing the underlying calculation.

Failure 3: it works now, but fails after reopen

A workbook that works in the author’s current session is not yet a reliable deliverable.

Session state can hide problems with unsaved notebook source, temporary Python objects, runtime startup, packages, or external services. The persistence test is therefore part of debugging, not a final cosmetic check.

Use this sequence:

  1. save until Boardflare reports the notebook as saved;
  2. close the workbook;
  3. reopen it in a fresh session;
  4. allow the Python runtime and publication registry to initialize;
  5. verify the worksheet outputs;
  6. change one representative workbook input;
  7. verify reactive recalculation;
  8. test the intended App/Edit presentation.

A brief #BUSY! during cold start is different from a workbook that never reaches publication. If #BUSY! persists, inspect runtime status, package/import failures, saved source loading, and whether execution reaches bf.publish().

This is also where author/operator testing matters. A workbook that only succeeds in the author’s warm session has not proved that another user can operate the saved application.

See App Mode and Sharing for the current save, reopen, and second-user boundary.

When the failure really is in the Python model

If workbook inputs are correct and publication is not involved yet, reduce the calculation to a known fixture.

Record:

  • the exact input rows;
  • the expected output;
  • the relevant assumptions;
  • the smallest function that should produce the result.

Then ask:

What is the earliest intermediate value that differs from the expected fixture?

In a reconciliation model, test candidate scoring separately from one-to-one assignment. In a forecast, test one model’s prediction separately from backtest aggregation. In an optimizer, inspect objective coefficients, constraints, and bounds before blaming the solver.

The maintained Boardflare templates use baseline and changed-input scenarios for the same reason: the workbook should prove that it recomputes from changed worksheet state rather than merely contain a correct static result.

Package failures belong at the browser/runtime boundary

Boardflare’s browser runtime is not the same environment as desktop Python. Pyodide is CPython compiled to WebAssembly for browsers, and package compatibility depends on what can run in that environment.

If an import works on a laptop but fails in the workbook:

  • check transitive dependencies, not just the top-level import;
  • distinguish pure-Python/Pyodide-compatible packages from packages that require unsupported native dependencies;
  • verify the package against the browser/Pyodide runtime rather than assuming a desktop wheel will work.

A package failure is not fixed by changing workbook formulas. The notebook child also permanently sets connect-src 'self', so notebook code cannot call arbitrary external origins directly. Use a separate managed/external integration for workflows that require unrestricted network access.

The Security and Data Flow guide describes Boardflare’s current network-isolation boundary.

Force failures before users find them

Do not validate only the happy path. Deliberately trigger representative failures:

  • blank a required input;
  • enter an invalid threshold;
  • change a worksheet shape expected by a binding;
  • request an unknown published output;
  • use a scenario that makes an optimization infeasible when that is possible;
  • close and reopen from a cold start.

The question is not merely whether the workbook fails. It is whether the failure appears at the correct boundary and tells the operator what to do next.

A reusable debugging sequence

When a workbook fails, inspect these boundaries in order:

Excel value
  ↓
BF input binding
  ↓
validated Python value
  ↓
model/intermediate result
  ↓
published output/function
  ↓
Excel consumer
  ↓
save/reopen + second-user behavior

At each arrow, inspect one value or status on both sides. The first boundary where correct state becomes incorrect is the layer to fix.

For current symptoms and recovery actions, use Troubleshooting and Reference.