Troubleshooting

<- Back to home

This page collects the most common adoption and integration problems. Most failures fall into one of three buckets:

  • config validation (ConfigError)

  • hook ordering or context usage (IntegrationError)

  • docs-generation or parser-registration alignment issues

First question: is each helper in the right place?

Helper

Where it belongs

configure_parsers(CONFIG_PATH)

module import time in environment.py

install(context, CONFIG_PATH)

before_all()

substitute_feature_variables(context)

before_all(), after install()

expand_scenario_cycles(context)

before_all(), after install()

configure_test_logging(...)

usually before_all(), after install()

configure_loggers(context)

usually before_all(), after install()

activate_feature_scope(context)

before_feature()

activate_scenario_scope(context)

before_scenario()

If a helper is in the wrong place, fix that first before chasing anything more subtle.

ConfigError: the config failed before runtime started

Typical causes:

  • the factory import path is wrong

  • a $ref points at an unknown object

  • a $var points at an unknown variable

  • an object depends on a narrower scope

  • duplicate names exist across config files

Factory import problems

Symptom: install() fails because a factory or converter is not importable.

Checks:

  • confirm the import path matches a real Python symbol

  • confirm the module is importable from the environment where Behave runs

  • if it is your own project code, confirm that the project layout makes that module visible to Python

Unknown $ref or $var

Symptom: config loading says that a referenced object or variable does not exist.

Checks:

  • spelling matters; object and variable names are exact

  • when you use a config directory, confirm the relevant file is inside the configured directory

  • remember that duplicate names fail fast instead of silently overriding one another

Wider-to-narrower scope dependency

Symptom: validation says an object cannot depend on an object from a narrower scope.

Mental model:

  • global can only depend on global

  • feature can depend on global or feature

  • scenario can depend on global, feature, or scenario

If the dependency direction points the other way, move the dependent object to a narrower scope or extract the shared value into a root variable.

IntegrationError: the config was valid, but the Behave wiring is wrong

Typical causes:

  • activate_feature_scope() or activate_scenario_scope() was called before install()

  • a helper was called from the wrong hook

  • a reserved or duplicate context name collided with something else

  • a helper that should only run once was called twice

Forgot install() or called it too late

Symptom: activation helpers complain that the toolkit is not installed.

Fix: call install(context, CONFIG_PATH) from before_all() before any scope-activation or optional runtime helper.

Scope already active

Symptom: activation says the scope is already active.

Fix: call activate_feature_scope(context) once from before_feature() and activate_scenario_scope(context) once from before_scenario().

Context-name collisions

Symptom: validation or logger configuration says a context name is already used.

Fix: rename inject_as (or the default object name) so it does not collide with:

  • another object in the same scope

  • a configured logger

  • the manager namespace such as toolkit

Feature-variable issues

{{var:name}} placeholders are still visible at runtime

Symptom: step text or scenario names still contain {{var:...}}.

Fix: call substitute_feature_variables(context) from before_all() after install().

Unknown feature variable

Symptom: substitution says a variable name is unknown.

Fix: define it in the root variables: section of the toolkit config. Feature placeholders do not read environment variables directly.

Unsupported feature-variable value type

Symptom: substitution says the resolved value type is unsupported.

Fix: {{var:name}} placeholders must resolve to a scalar string, number, or boolean. Move structured values back into YAML object fields instead.

Parser helpers are not taking effect

Symptom: a custom type works in one environment but not when Behave imports steps, or docs generation misses the type.

Fixes:

  • call configure_parsers(CONFIG_PATH) at module import time, not inside before_all()

  • if you use a converter-based type, provide pattern unless the converter already exposes the necessary parse metadata

  • confirm the same config path is used for both runtime and docs generation

Scenario cycling problems

@cycling(...) on Scenario Outline

Symptom: scenario cycling rejects the scenario.

Fix: @cycling(N) only works on plain Scenario. Use Examples for Scenario Outline.

Invalid cycle tag syntax

Symptom: @cycling(foo) or similar fails.

Fix: use @cycling(3) with a positive integer.

Generated step docs are missing examples or types

No examples attached to steps

Checks:

  • confirm --features-dir points at the correct Behave project

  • if your feature files use {{var:name}}, pass --config-path

  • confirm your suite actually contains matching feature-step usages

Custom types missing from generated docs

Checks:

  • confirm configure_parsers(CONFIG_PATH) runs at import time in environment.py

  • confirm the parser config is in the file or directory you pass to configure_parsers(...)

Use the manager to inspect the current state

The manager attached at context.toolkit is often the fastest way to see what the toolkit thinks is configured.

def before_scenario(context, scenario):
    activate_scenario_scope(context)
    print("Configured objects:", context.toolkit.list_objects())
    print("Configured loggers:", context.toolkit.list_loggers())
    print("Scenario objects:", context.toolkit.active_objects("scenario"))
    print("report_path spec:", context.toolkit.spec("report_path"))

Useful methods to remember:

  • list_objects()

  • list_loggers()

  • spec(name)

  • instance(name)

  • logger(name)

  • objects_for_scope(scope)

  • active_objects(scope)

Local validation commands

When in doubt, run the same validation commands the repository uses:

python -m unittest discover -s tests -v
python -m mypy src tests test_support.py
python -m pylint src tests test_support.py
python -m compileall src tests test_support.py
python -m sphinx -W --keep-going -b html docs docs/_build/html

If the problem persists after that, capture the exact config snippet, the hook wiring, and the full error message. Those three pieces usually make the root cause obvious.