Troubleshooting
This page gathers the most common things that go wrong in a RISE
workflow, how to diagnose them, and what to try. The single most
useful diagnostic is decipher – always run it first when a
retcode comes back non-zero.
Deciphering return codes
Most RISE entry points (solve, filter, estimate,
forecast, simulate) return a retcode integer alongside
their main outputs. A non-zero value signals a problem; decipher
turns it into a sentence:
[m, retcode] = solve(m);
if retcode ~= 0
decipher(retcode) % prints the explanation
msg = decipher(retcode); % or capture as a string
end
decipher accepts a scalar or a vector of codes. Codes are organised
by the stage of the pipeline that emits them.
Codes by category
Range |
Stage |
Codes |
|---|---|---|
1-7, 11 |
Evaluating the system |
|
21-28, 201-263 |
Solving the system |
|
301-313 |
Filtering / likelihood |
|
-403 to 405, 4002 |
Optimization (mode search) |
|
500 |
Data |
|
603-604 |
Code generation (writing functions to disk) |
|
701-707 |
Forecasting / simulation |
|
801 |
VAR |
|
The canonical table (the single source of truth) lives in
m/+utils/+error/registry.m; decipher reads it and prints the
message for a given code. decipher is also re-exposed as a
top-level shortcut (m/shortcuts/decipher.m), and the codes are
available as named constants via utils.error.codes.
When the steady state does not solve
The first thing solve does is build a steady state. The most common
causes of failure (retcodes 1, 11):
Parameters not all assigned. Check
any(isnan(m.parameter_values))(orisnan(m)for the same thing on the model object). Missing parameters surface as NaN propagation through the residual function.Non-stationary model on a stationary solver. If the model has a balanced growth path, tell RISE:
m = set(m, 'solve_bgp', true);
User-supplied analytical steady state. If a
@steady_state_modelblock or an externalsstate_fileis in play, the most likely cause of failure is a bug in that block or file rather than in RISE. Verify against a small test case (parameters where the steady state is known by hand).Variables that can only be positive (consumption, capital, prices) freely sampled into the negative orthant by the steady-state solver. Either set their bounds accordingly, or declare them as log variables:
@endogenous(log) C, K, P
Starting point. The default
solve_initialization='backward'suits most models; for a model where backward solution diverges, try'zeros'or'random':m = set(m, 'solve_initialization', 'zeros');
Tolerances or iteration caps. The steady-state solver is controlled by
fix_point_TolFunandfix_point_maxiter. Loosen the tolerance or bump the iteration cap if the residuals are merely close to zero.
When the model does not solve (but the steady state does)
If the steady state is fine but the policy / state-space solution
fails, you are looking at a Blanchard-Kahn-style problem (retcodes
22, 24, 25) or numerical breakdown (23, 223):
Indeterminacy / no solution (
22,25): typically a mis-specified expectations channel or a missing equation pinning a forward-looking variable. Check that the number of forward-looking variables matches the number of structural shocks plus exogenous jumps.Explosive solution (
24): a sunspot in disguise, or a parameter region where the system has no stable rational-expectations equilibrium. Move the parameter vector, or constrain the prior.Explosion limit reached (
23): the solver’s iterates grew beyondfix_point_explosion_limit(default1e12); often a symptom of a bad starting policy from regime switching with too few outer iterations – increasefix_point_maxiter.Complex solution (
223): generally means the chosen solver is not appropriate for the model class (e.g. a non-Markovian solver on a regime-switching model). Try a different solver:m = set(m, 'solver', 'mfi');
Log-expansion of a near-zero steady state (
27): a variable declared@endogenous(log)has a steady state too close to zero. Either remove thelogannotation or rescale the model so the steady state is well away from the floor.
When filtering or likelihood fails
The estimation engine wraps the filter inside the objective; a
retcode from the filter propagates up as a -Inf log
likelihood. The frequent codes:
305 / 313 (covariance of forecast errors not positive definite, or positive definite but determinant 0): typically a sign that two observables are nearly collinear, or that an observable has near-zero variance in the simulated distribution. Check
cov(data)and add a small measurement error if needed.306 (unlikely parameter vector): the prior puts essentially zero mass on the candidate. Verify the prior bounds match the model scale.
307 (NaN/Inf/complex log prior): a prior distribution returned a non-finite value on the candidate vector. Print the candidate and check it against each prior’s support.
308 (inconsistent ergodic probabilities): the regime-switching transition matrix is mis-built; verify
sum(m.markov_chains.transition_matrix, 2) == 1.309 (endogenous priors failed): the user-supplied
estim_endogenous_priorscallback errored or returned a non-finite value.310 / 311 (NaN/Inf in initial state vector / covariance matrix): the unconditional moments don’t exist; usually a unit-root variable that was not declared as such.
312 (NaN/Inf/complex likelihood): the filter completed but the log-likelihood is not a real finite scalar. Usually a downstream consequence of a near-singular forecast covariance.
Debug toggles
Toggle |
Effect |
|---|---|
|
general verbose mode; prints intermediate diagnostics in
m = set(m, 'debug', true);
|
|
detailed parser tracing (model-file processing): m = rise('mymodel', 'parse_debug', true);
|
|
per-iteration diagnostics from the fixed-point solvers (steady state, regime-switching solve, loose commitment): m = set(m, 'fix_point_verbose', true);
|
|
|
Tightening tolerances and iteration caps
When a solve / filter / estimate “almost works”, these are the knobs:
Option |
Controls |
Default |
|---|---|---|
|
convergence tolerance for fixed-point solvers (steady state, MS solve, loose commitment) |
|
|
max iterations for the same |
|
|
max iterations for the discretion / stochastic-replanning fixed point |
|
|
absolute-value cutoff that triggers a “diverged” early stop |
|
|
optimizer-side tolerances |
|
|
optimizer-side iteration / eval caps |
optimizer-specific |
Profiling
When a workflow is slow but correct, the recipe is the same as for any MATLAB code:
profile -timer 'cpu' on
% the slow call (e.g. an estimation)
m = estimate(m, 'data', db, 'priors', priors);
profile off
profile viewer
Reading the resulting report, the bottleneck candidates ranked by how often they bite in RISE:
Symbolic differentiation (one-shot, parse time). Dominant on large models – 5000+ equations may take minutes. Once paid, it is cached in the model’s
+routinespackage and not redone unless the model file changes.Evaluation of compiled derivatives, per iteration of the objective. The standard bottleneck inside MCMC and posterior maximization.
Forecasting step inside filtration. For multi-regime models the regime-conditional forecast is the most expensive part of the likelihood evaluation.
Loops in filtration for long sample / many regimes – usually vectorised already, but worth checking after a user-defined filter change.
Automatic differentiation if
solve_order >= 2and higher-order derivatives are recomputed every iteration – consider caching at compile time where the model structure allows.Inaccuracies in numerical derivatives – not a speed problem per se, but a convergence problem that looks like one when the optimizer wastes iterations on noisy gradients.
Disk I/O if
solve_function_mode = 'disk'is set; default is in-memory. Disk mode is opt-in; switch back if your model is small enough.
The estimation summary printed by print_estimation_results reports
the wall-clock time, the number of function evaluations, and the
optimizer used – a useful first cut before reaching for profile.