Flow cytometry troubleshooting

Fixing the flowCore “$SPILLOVER size discrepancy” error

Your FCS file looks fine, but R refuses it. Here is exactly what the error means, why it happens, and three ways to fix it.

If you have ever fed an FCS file into flowCore and been stopped cold by Error: $SPILLOVER size discrepancy, the good news is that your data is almost certainly fine. The problem is one malformed metadata keyword — and it is a known, fixable issue, most often coming from a BD FACSDiva export.

On this page
  1. What the error actually means
  2. The $SPILLOVER format, in one line
  3. Why BD FACSDiva produces malformed matrices
  4. Step 1 — Diagnose the exact malformation
  5. Step 2 — Three ways to fix it
  6. Preventing it next time

What the error actually means

flowCore — the R/Bioconductor package that most cytometry pipelines are built on — reads the compensation matrix from a keyword in the FCS file's TEXT segment called $SPILLOVER (or $SPILL in FCS 3.1+). When it parses that keyword, it counts the values. If the count does not match what the keyword says it should contain, flowCore raises a size discrepancy and refuses to read the file.

In other words: the error is not about your event data at all. The measurements are intact. It is purely a bookkeeping mismatch inside one metadata string.

The $SPILLOVER format, in one line

The compensation matrix is stored as a single comma-separated string with a very specific shape:

n, name₁, name₂, …, nameₙ, m₁₁, m₁₂, …, mₙₙ

That is:

So a valid $SPILLOVER always contains exactly 1 + n + n² comma-separated tokens. A 3-channel matrix has 1 + 3 + 9 = 13 tokens. When that count is off — even by one — flowCore throws the size discrepancy.

Why BD FACSDiva produces malformed matrices

The single most common source of this error is a compensation matrix that was edited by hand in BD FACSDiva. When a user manually adjusts compensation and the workspace is exported, the written $SPILLOVER string can end up with a declared count n that no longer matches the number of names or values actually present. A frequent culprit is a stray trailing comma, which adds an empty token and pushes the total past 1 + n + n².

The matrix is usually still readable by a human — the numbers are all there. It is just that the self-describing count at the front is wrong, and flowCore validates that count strictly. FlowJo, by contrast, is tolerant: it quietly ignores or repairs the bad keyword and writes a clean one the next time you save the workspace. That difference is exactly why a file can open perfectly in FlowJo and fail instantly in R.

The short version: a strict reader (flowCore) counts the tokens and finds the count doesn't match the declared size. A tolerant reader (FlowJo) shrugs and moves on. Your data is fine either way.

Step 1 — Diagnose the exact malformation

Before fixing anything, it helps to see precisely what is wrong: how many tokens the keyword declares versus how many it actually contains. You can do this without installing anything and without uploading your file anywhere.

The free FlowVision FCS Validator runs entirely in your browser. Drop the file in and it parses the $SPILLOVER keyword the same way flowCore does, then reports the declared size, the expected token count, the actual token count, and — when it can — a corrected matrix string you can copy. If the discrepancy is a simple trailing-comma or off-by-one count, it will show you the fix directly.

Diagnose your file in the browser — no upload, no account.

Open the free FCS Validator →

Step 2 — Three ways to fix it

Option A — Round-trip through FlowJo

The classic workaround: open the file (or workspace) in FlowJo and re-save it. Because FlowJo repairs the keyword on save, the re-exported file carries a clean $SPILLOVER that flowCore will accept. This works, but it requires a FlowJo licence — which is the whole reason many people are looking for an alternative in the first place.

Option B — Paste the corrected matrix string

If the malformation is a simple count mismatch (the most common case), the FCS Validator above will give you a corrected $SPILLOVER string with the right leading count and exactly n × n values. You can use that to overwrite the keyword in your analysis pipeline, or to hand-verify what the matrix should be. Always sanity-check the matrix values before relying on them — the validator re-counts tokens, it does not re-derive your compensation.

Option C — Strip or replace the keyword in R

If you compensate downstream anyway (for example, you apply your own spillover matrix), you can read the file with a tolerant parser and drop the offending keyword. A common pattern is to read the raw file, remove or overwrite the SPILLOVER / SPILL keyword, and then construct the compensation explicitly from a matrix you trust rather than the one embedded in the file.

This is the most robust long-term option if you process many files programmatically: never depend on the embedded matrix being well-formed — supply your own.

Preventing it next time

None of this requires expensive software. The error looks alarming, but it is a one-keyword bookkeeping issue with a clear fix — and you can see exactly what is wrong with your file in a few seconds.

Want to analyze the file, not just fix it?

FlowVision desktop opens FACSDiva, Cytek, Sony and Beckman Coulter files, handles compensation and spectral unmixing, and exports back to FlowJo (.wsp) and Gating-ML — no lock-in. Windows + macOS, $99 lifetime.

Download the free trial →

Related: FCS Validator · FCS Viewer · FlowVision vs FlowJo · All free FCS tools