Troubleshooting & Known Failure Modes#
Each entry gives the symptom you will actually see, the cause, and the workaround.
Installation#
conda env create fails on deblur → sortmerna#
package deblur-1.1.1 requires sortmerna 2.0, but none of the providers
can be installed
Cause. A defect in the upstream QIIME 2 2026.7 linux-64 distribution file:
it pins zlib=1.3.2, while every sortmerna 2.0 build in bioconda requires
zlib >=1.2.11,<1.3.0a0. The two cannot be satisfied together.
Workaround. deblur is not used anywhere in this tutorial. Download the
environment file, delete the deblur, q2-deblur and sortmerna lines, and
create the environment from your edited copy.
qiime gglasso pca fails with TemplateNotFound#
Cause. A non-editable install built before the fix did not ship
_pca/assets/index.html — it was missing from package_data.
Workaround. Reinstall from a current checkout, or use pip install -e ..
pip silently breaks a working environment#
Cause. pip cannot see conda’s pins and will install a wheel over
numpy=2.4.2.
Workaround. Always pip install --no-deps inside a QIIME 2 environment.
Check with conda list numpy pandas scipy afterwards.
q2-gglasso#
--p-rank always fails#
NotImplementedError: Explicit rank selection requires a GGLasso version that
exposes an explicit low-rank rank parameter...
Cause. No released GGLasso (up to and including 0.3.0) can fix the rank of
the low-rank component. It exposes only the continuous mu1 penalty and reports
the achieved rank as an output. The parameter is registered but guarded so it
raises rather than being silently ignored.
Workaround. Size the low-rank block through mu1: a larger mu1 gives a
smaller rank. Scout a small mu1 grid and read the achieved rank out of the
solution — see Choosing the Latent Rank.
Explicit rank selection becomes available when GGLasso PR #50
(fix_latent_rank) is merged and released.
qiime gglasso pca crashes on a solution that has no low-rank part#
Cause. pca reads solution/lowrank_, which only exists when the problem
was solved with --p-latent True.
Workaround. Run solve-problem with --p-latent first. A sparse-only (SGL)
solution cannot be used with pca.
pca refuses: n_components (3) exceeds the rank of the low-rank component (2)#
Cause. --p-n-components defaults to 3, but the achieved rank of the
low-rank component falls as mu1 rises, and you cannot take more components
than there are. On the 300-ASV Atacama data the map is μ = 15 → rank 2,
μ = 10 → rank 5, μ = 7.5 → rank 10. The default therefore breaks on the
headline fit at μ = 15.
Workaround. Pass --p-n-components 2 at μ = 15, or in a script derive it
from the solution rather than hardcoding:
rank = np.linalg.matrix_rank(np.asarray(root["solution/lowrank_"]), tol=1e-8)
n_components = min(3, rank)
This is a guard doing its job, not a bug: earlier versions accepted the
mismatch and failed later inside utils.PCA with an unrelated matmul error.
The taxonomy join returns all-NaN instead of raising#
Cause. The transformed table was built with --p-no-keep-original-id, so its
features are ASV-1 … ASV-p positional labels, while the taxonomy artifact is
keyed on 32-character hexadecimal feature IDs. df.join(tax) finds no overlap
and fills with NaN, and .reindex() does the same. Nothing raises, so the
failure reads as “this dataset has no taxonomy”.
Workaround. Rebuild with --p-keep-original-id (the default). Do not try to
map ASV-k back through an abundance ranking — ASV-k is assigned by position,
and ties in total abundance make the mapping ambiguous. On the 300-ASV table,
209 of 300 features share a total-abundance value and are therefore at risk.
Measured against the plugin’s own ordering, a rank-based mapping placed 146 of
300 features differently. Within a tie group a feature can still land correctly
by coincidence, which is why the measured count is below the at-risk count — but
you cannot tell which ones did. See
Interpretation.
How to notice. Assert rather than eyeball:
assert tax.reindex(features)["Taxon"].notna().all().
qiime gglasso pca crashes with AttributeError on metadata#
Cause. --m-sample-metadata-file is optional in the signature, but the
action dereferences it unconditionally.
Workaround. Always pass --m-sample-metadata-file. Treat it as required.
transform-features demands a taxonomy I don’t have#
Cause. --i-taxonomy is a required input but the function body never uses
it. This is a registration wart, not a real dependency.
Workaround. Pass any valid FeatureData[Taxonomy] artifact; its contents do
not affect the result.
build-groups output cannot be fed to solve-problem#
Cause. build-groups emits a TensorData artifact, but solve-problem
takes group_array as a List[Int] parameter. They do not chain through the
QIIME 2 type system.
Workaround. Export the artifact and pass the group index explicitly as
--p-group-array. See
Multiple Graphical Lasso.
The .qzv opens as a blank white page#
Cause. A bokeh version mismatch: the visualizer emits a bokeh 3 document while the page loads a bokeh 2.4.3 runtime. There is no Python traceback — the failure is entirely client-side.
Workaround. Fixed in current q2-gglasso, which injects version-matched bokeh
resources instead of hardcoding a CDN URL. If you see it, you are on an older
build. Confirm by unzipping the .qzv and grepping index.html for bokeh-2..
Model selection ran even though I only wanted a single fit#
Cause. The solver performs model selection whenever at least one grid holds
more than one value, so a single fit requires lambda1 and lambda2 — plus
mu1 on a latent problem — to each resolve to exactly one value. Leaving
--p-lambda2-min / --p-lambda2-max unset does not count as one value: the
solver expands an unset pair of bounds to the 5-point default
np.logspace(-1, -4, 5) and warns Default values for lambda2 have been used..
That alone switches model selection on, so a lone
--p-lambda1-min 0.5 --p-lambda1-max 0.5 still gives you a path. (The
single-instance solver does not otherwise use lambda2; it only decides this
branch.)
Workaround. Pin λ₂ explicitly — pass the same value to
--p-lambda2-min and --p-lambda2-max — and do the same for --p-mu1-min /
--p-mu1-max on a latent problem. Check the result by looking for a
modelselect_stats group in the solution: a single fit has none, and summarize
reduces its statistics tab accordingly.
q2-classo#
--p-cv--nlam has two dashes — is that a typo?#
No. The parameter really was named cv__nlam with a double underscore, which
QIIME 2 renders as --p-cv--nlam.
It is now spelled cv_nlam (--p-cv-nlam). The old spelling still works but
emits a DeprecationWarning. Passing both with different values raises — but
only if cv_nlam was changed from its registered default of 100. QIIME 2 fills
that default in whether or not you typed it, so 100 is indistinguishable from
“not given” and is treated as unset: --p-cv-nlam 100 --p-cv--nlam 50 does not
raise — it silently uses 50.
qiime classo classify --p-concomitant True is rejected#
Cause. The concomitant formulation is not available for classification.
classify has no concomitant parameter, and the underlying solver forces
formulation.concomitant = False for classification problems.
Workaround. Use the Huber hinge loss: --p-huber True, tuned via --p-rho.
See Concomitant Formulation.
qiime classo --help lists two actions called “regress”#
Cause. classify was registered with name="regress".
Workaround. Fixed in current q2-classo. If you see it, your install predates the fix — the action still works, it is only mislabelled.
Every plot pane in the summarize .qzv is blank#
Cause. The plot-writing calls were commented out while the templates still
referenced 16 <iframe> files. No error was raised. The panes rendered empty.
Workaround. Fixed in current q2-classo. A regression test now asserts that every iframe the templates reference has something that writes it.
NameError: name 'xGraph' is not defined#
Cause. A typo (xGrpah) on the non-log-scale branch, reachable via
--p-cv-logscale False.
Workaround. Fixed in current q2-classo.
Both plugins#
A misspelled enum value fails at runtime, not on the command line#
ValueError: Unknown transformation name, use clr and not 'clrr'
Cause. Neither plugin declares Choices() on its string parameters, so QIIME 2
accepts any string and the check happens inside the function. Affects
--p-transformation (clr/mclr), --p-method (scaled/unscaled),
--p-reg (GGL/FGL), --p-path-scale (log/linear) and the various
--p-*-numerical-method parameters.
Workaround. Check spelling against the
parameter reference. The *_numerical_method
parameters default to the literal string "not specified", so a typo there is
silently accepted.
The CLR transform produces obviously wrong values#
Cause (historical). Zero imputation used a chained pandas assignment that
becomes a silent no-op under Copy-on-Write, so no pseudo count was ever added.
The failure surfaced far from its origin, as
AssertionError: Add pseudo count before using clr.
Workaround. Fixed in current q2-gglasso.