Errors
How to read factrix errors and which exception class to catch.
TL;DR¶
import factrix as fx
from factrix.metrics import ic
try:
results = fx.evaluate(
data,
metrics={"ic": ic(inference=fx.inference.NEWEY_WEST)},
factor_cols=["factor"]
)
except fx.UserInputError as exc:
# User typed the wrong thing — typo, unknown name, wrong column.
# The message carries a fuzzy suggestion + a docs link.
print(exc)
except fx.IncompatibleAxisError as exc:
# Axis miswire.
...
except fx.InsufficientSampleError as exc:
# Sample threshold is below the required hard floor.
# exc.actual_periods and exc.required_periods carry details.
...
except fx.FactrixError as exc:
# Catch-all for anything else factrix raises.
...
All factrix-raised exceptions inherit from FactrixError, so a single
except fx.FactrixError blocks every library-raised failure.
Exception hierarchy¶
FactrixError # base
├── IncompatibleAxisError # (scope, density, metric) is not a legal cell
├── IncompatibleInferenceError # inference= outside the metric's applicable-inference allowlist
├── InsufficientSampleError # T below SampleThreshold on a TIMESERIES/PANEL procedure
├── UserInputError # named-set typo / type mismatch / dataset schema error
└── CycleError # MetricSpec.requires declares a dependency cycle
| Exception | When you see it | What it carries |
|---|---|---|
IncompatibleAxisError |
(scope, density, metric) is not a legal cell |
— |
IncompatibleInferenceError |
inference= outside the metric's applicable_inference allowlist |
.func_name, .value, .applicable |
InsufficientSampleError |
T below the procedure floor |
.actual_periods, .required_periods |
UserInputError |
Unknown metric, column not in data, wrong type | structured .field, .value, .candidates, .suggestions, .expected, .docs_url |
CycleError |
A custom metric's MetricSpec.requires forms a dependency cycle |
— |
Error → fix mapping¶
Concrete messages, what triggers them, and where to look for the fix.
Data-schema failures¶
| Message hint | Trigger | Fix |
|---|---|---|
factor_cols 'X' not in data columns |
Typo or wrong column name | Check data.columns; pass the actual name to factor_cols=. See Data schema. |
forward_return column missing |
Forgot the preprocess step | compute_forward_return(raw, forward_periods=h) before evaluate. See Preparing data. |
Structural and sample failures¶
| Exception / message | Trigger | Fix |
|---|---|---|
IncompatibleAxisError: (scope, density, metric) is not a legal cell |
Combination that the dispatch table never registers | Use compatible axes. Check list_metrics or inspect_data to find applicable metrics. |
InsufficientSampleError: T below required |
Sample size below the procedure's hard floor | Read .actual_periods and .required_periods. The fix is either more data, or switching to a less restrictive metric. |
User-input failures (UserInputError)¶
Every UserInputError carries structured attributes (see Reading a UserInputError). Common triggers and fix paths:
| Message hint | Trigger | Fix |
|---|---|---|
unknown metrics='...' |
Typo or metric not applicable to the data | inspect_data(data).usable enumerates the metrics applicable to the data shape. See list_metrics for the full catalog. |
invalid expand_over=[...] |
One or more expand_over keys missing on some results' params |
The message lists every (factor, missing_key) pair in one pass. All results in the family must carry the key in .params; populate it consistently, or drop the key from expand_over. A key found on .metadata instead is called out separately — bookkeeping never partitions a family. |
Expected: list[EvaluationResult], got ... |
Passing the wrong artifact type to a screening function | Screening (bhy, partial_conjunction, bhy_hierarchical) consumes list[EvaluationResult]. |
Reading a UserInputError¶
Every user-facing raise that takes a named input renders the same three-part message:
bhy(): unknown expand_over='univere_id'
Did you mean: "universe_id"?
Available: ['regime_id', 'sector', 'universe_id']
Docs: https://awwesomeman.github.io/factrix/api/bhy#expand_over
| Line | What to look at |
|---|---|
<func_name>(): unknown <field>=<value> |
Which kwarg / column triggered the raise, and what value was received. |
Did you mean: "..." |
Top-3 fuzzy candidates (omitted when nothing matches above the cutoff). |
Available: [...] |
The full legal set. |
Docs: https://... |
The function's deployed-docs anchor. |
For type / shape mismatches, the second line reads Expected: <shape> instead of Did you mean: ....
Programmatic recovery¶
The structured attributes are the contract — read them, do not parse the rendered message:
import factrix as fx
bad: dict[str, object] = {}
for factor_col in candidates:
try:
results = fx.evaluate(data, metrics=metrics, factor_cols=[factor_col])
except fx.UserInputError as exc:
bad[exc.field] = exc.value
# exc.suggestions carries top-3 fuzzy matches when applicable
| Attribute | Meaning |
|---|---|
func_name |
The calling function (e.g. "bhy", "evaluate"). |
field |
The kwarg / column name that failed validation. |
value |
The value the caller passed in. |
candidates |
Sorted tuple of legal names (named-set branch); () otherwise. |
suggestions |
difflib top-3 matches against candidates; () when none. |
expected |
Human-readable shape (mismatch branch); None otherwise. |
docs_url |
Resolved deployed-docs URL for the function. |
Class reference¶
Autodoc anchors for cross-references of the form [FactrixError][factrix.FactrixError] from any docs page.
Base¶
factrix.FactrixError ¶
Bases: Exception
Base for all factrix-raised errors.
User-input failures¶
factrix.UserInputError ¶
UserInputError(*, func_name: str, field: str, value: object, candidates: Iterable[object] | None = None, expected: str | None = None, docs_path: str)
Bases: FactrixError, ValueError
User-supplied input does not match expected names or types.
Raised for typos in named-set kwargs (metric / estimator / params key
/ column name) or input-type mismatches. Multi-inherits from
:class:ValueError so ecosystem code (pytest.raises(ValueError),
generic except ValueError) keeps working.
Structured attributes carry the diagnostic so callers (sub-issue raises, LLM agents) do not parse the rendered message:
func_name: the calling function name (no parens)field: the kwarg / column name that failed validationvalue: the value the caller passed incandidates: tuple of legal names (named-set branch); empty otherwisesuggestions: difflib top-3 fuzzy matches againstcandidatesexpected: human-readable shape (type-mismatch branch);Noneotherwisedocs_url: deployed-docs URL for the function
Structural and sample failures¶
factrix.IncompatibleAxisError ¶
Bases: FactrixError
(scope, density, metric) tuple is not a legal analysis cell.
Covers e.g. density=SPARSE paired with metric=IC, or
(INDIVIDUAL, DENSE) with metric=None.
factrix.IncompatibleInferenceError ¶
Bases: FactrixError
inference= is not in the metric's applicable-inference allowlist.
Each metric that exposes inference= declares an
applicable_inference frozenset of the methods it actually
dispatches. Passing anything outside it — a valid Inference the
metric does not vet (e.g. HansenHodrick to ic) or a non-
Inference object — raises here instead of silently running an
unintended test or falling back to the default.
Structured attributes carry the diagnostic so callers do not parse the rendered message:
func_name: the calling metric name (no parens)value: the value the caller passed asinferenceapplicable: tuple of allowed inference names for that metric
factrix.InsufficientSampleError ¶
Bases: FactrixError
T < MIN_PERIODS_HARD for a TIMESERIES procedure.
Below the floor, Newey-West (NW) heteroskedasticity-and-autocorrelation-consistent (HAC) SE is too biased for primary_p to be
trustworthy. Raised at evaluate-time. actual_periods
and required_periods carry the numbers so callers can recover or
aggregate programmatically (review fix UX-3).
Custom-metric wiring failures¶
factrix.CycleError ¶
Bases: FactrixError
Raised when MetricSpec.requires declares a dependency cycle.
A :class:FactrixError, so except factrix.FactrixError catches it
alongside every other library-raised failure.