jenkins-jobs: No jjb.cli.subcommands extensions found (fix)

On setuptools 82 or newer, jenkins-jobs (Jenkins Job Builder 6.5.0, the latest) fails with stevedore.exception.NoMatches: No jjb.cli.subcommands extensions found. The cause is No module named 'pkg_resources' in jenkins_jobs/registry.py. Tested fix: pip install "setuptools<81".

1. The error: jenkins-jobs 6.5.0 with setuptools 84

pip install jenkins-job-builder==6.5.0 (the latest release, 2026-05-23) into a Python 3.11.17 venv, then setuptools 84.2.1:

$ jenkins-jobs --version
ERROR:stevedore.extension:Could not load 'delete': No module named 'pkg_resources'
ERROR:stevedore.extension:Could not load 'delete-all': No module named 'pkg_resources'
ERROR:stevedore.extension:Could not load 'get-plugins-info': No module named 'pkg_resources'
ERROR:stevedore.extension:Could not load 'list': No module named 'pkg_resources'
ERROR:stevedore.extension:Could not load 'test': No module named 'pkg_resources'
ERROR:stevedore.extension:Could not load 'update': No module named 'pkg_resources'
Traceback (most recent call last):
  File "/path/to/venv/bin/jenkins-jobs", line 10, in <module>
    sys.exit(main())
             ^^^^^^
  File "jenkins_jobs/cli/entry.py", line 177, in main
    jjb = JenkinsJobs(argv)
          ^^^^^^^^^^^^^^^^^
  File "jenkins_jobs/cli/entry.py", line 60, in __init__
    self.parser = create_parser()
                  ^^^^^^^^^^^^^^^
  File "jenkins_jobs/cli/parser.py", line 112, in create_parser
    extension_manager.map(parse_subcommand_args, subparser)
  File "stevedore/extension.py", line 377, in map
    raise NoMatches(f'No {self.namespace} extensions found')
stevedore.exception.NoMatches: No jjb.cli.subcommands extensions found

The real cause is in the first lines, not the last one. Every jenkins-jobs subcommand (test, update, delete, …) is a stevedore plugin, and each one imports jenkins_jobs/registry.py, whose line 22 is a plain import pkg_resources. setuptools 82.0.0 removed that module, so stevedore logs Could not load '…': No module named 'pkg_resources' for every subcommand and then fails with NoMatches: No jjb.cli.subcommands extensions found. jenkins-jobs test jobs/ fails the same way. jenkins_jobs/xml_config.py line 19 imports it too.

2. Fix: pin setuptools below 81 in the JJB environment (tested)

$ pip install "setuptools<81"    # gave 80.10.2
$ jenkins-jobs --version
jenkins_jobs/registry.py:22: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
  import pkg_resources
Jenkins Job Builder version: 6.5.0

With a one-job YAML file (- job: {name: hello, builders: [shell: echo hello]}), jenkins-jobs test jobs/ then printed the job XML and exited 0. There is no newer JJB release to upgrade to: 6.5.0 is the latest on PyPI, and on the opendev master branch registry.py still has import pkg_resources on line 22 (checked 2026-10-24). JJB lists setuptools as a dependency with no upper bound, so a plain pip install -U can pull in setuptools 82+ again: put setuptools<81 in your requirements or constraints file next to jenkins-job-builder.

3. Hide the deprecation warning

On setuptools 80.x every run prints the pkg_resources is deprecated as an API warning. It is harmless; in CI you can silence it:

$ PYTHONWARNINGS="ignore:pkg_resources is deprecated as an API" jenkins-jobs test jobs/

In our run that removed the warning and the job XML was still printed. If JJB runs in its own Docker image or tox env, set the pin and the variable there, not on the Jenkins controller.

Related: No module named 'pkg_resources' (general fix) · Ansible pip module · supervisord.

Frequently asked questions

Is there a Jenkins Job Builder version without pkg_resources?

Not yet: 6.5.0 (2026-05-23) is the latest release and the opendev master branch still imports pkg_resources in registry.py (checked 2026-10-24).

Why does the error say no extensions found instead of pkg_resources?

stevedore catches the ImportError for each subcommand plugin, logs it as an ERROR line, and then raises NoMatches because none of the subcommands loaded.

Written with AI assistance. Measured on 2026-10-24 on Linux with jenkins-job-builder 6.5.0, stevedore from the same install, CPython 3.11.17, setuptools 80.10.2 and 84.2.1. Output pasted unedited except shortened paths. PlainTables is our extension; Jenkins Job Builder is free.