RuntimeError - Association not found for auth_source_ldap after upgrade to 3.18.2

After upgrading our Foreman 3.17.2/Katello 4.19.2 installation to 3.18.2/4.20.1, our integration script can no longer fetch external LDAP groups via the API. When executing the following command:

$ curl -sS -H "Content-Type: application/json" -u "$USERNAME:$PASSWORD" \
    "https://foreman.example.com/api/auth_source_ldaps/4/external_usergroups?organization_id=1&per_page=10000"

The API returns this error response:

{
  "error": {"message":"Association not found for auth_source_ldap"}
}

The upgrade was successful, and there were no errors in foreman-installer log.

LDAP authentication works perfectly. Users can log in through the Foreman UI, and everything looks fine in the web interface. Only this API endpoint is broken.

I tried upgrading the instance further to 3.19.1 / 4.21.0 hoping the issue would be resolved, but the error persists.

I successfully reproduced this on a second, brand-new Foreman 3.17.2 / Katello 4.19.2 setup with minimal data. Upgrading that test environment to 3.18.2 broke the endpoint in the exact same way.

When the curl command is executed, the following stack trace is printed to /var/log/foreman/production.log:

2026-08-05T21:09:03 [I|app|8433c989] Started GET "/api/auth_source_ldaps/4/external_usergroups?organization_id=1&per_page=10000" for 172.28.96.106 at 2026-08-05 21:09:03 +0300
2026-08-05T21:09:03 [I|app|8433c989] Processing by Api::V2::ExternalUsergroupsController#index as JSON
2026-08-05T21:09:03 [I|app|8433c989]   Parameters: {"organization_id"=>"1", "per_page"=>"10000", "apiv"=>"v2", "auth_source_ldap_id"=>"4", "external_usergroup"=>{}}
2026-08-05T21:09:03 [I|app|8433c989] Authorized user admin(Admin User)
2026-08-05T21:09:03 [W|app|8433c989] Action failed
2026-08-05T21:09:03 [I|app|8433c989] Backtrace for 'Action failed' error (RuntimeError): Association not found for auth_source_ldap
 8433c989 | /usr/share/foreman/app/controllers/api/base_controller.rb:90:in `parent_scope'
 8433c989 | /usr/share/foreman/app/controllers/api/base_controller.rb:75:in `resource_scope'
 8433c989 | /usr/share/foreman/app/controllers/api/v2/external_usergroups_controller.rb:18:in `index'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/abstract_controller/base.rb:215:in `process_action'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_controller/metal/rendering.rb:165:in `process_action'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/abstract_controller/callbacks.rb:234:in `block in process_action'
 8433c989 | /usr/share/gems/gems/activesupport-7.0.10/lib/active_support/callbacks.rb:118:in `block in run_callbacks'
 8433c989 | /usr/share/foreman/app/controllers/concerns/foreman/controller/timezone.rb:10:in `set_timezone'
 8433c989 | /usr/share/gems/gems/activesupport-7.0.10/lib/active_support/callbacks.rb:127:in `block in run_callbacks'
 8433c989 | /usr/share/foreman/app/models/concerns/foreman/thread_session.rb:32:in `clear_thread'
 8433c989 | /usr/share/gems/gems/activesupport-7.0.10/lib/active_support/callbacks.rb:127:in `block in run_callbacks'
 8433c989 | /usr/share/foreman/app/controllers/concerns/foreman/controller/topbar_sweeper.rb:12:in `set_topbar_sweeper_controller'
 8433c989 | /usr/share/gems/gems/activesupport-7.0.10/lib/active_support/callbacks.rb:127:in `block in run_callbacks'
 8433c989 | /usr/share/gems/gems/audited-5.8.0/lib/audited/sweeper.rb:16:in `around'
 8433c989 | /usr/share/gems/gems/activesupport-7.0.10/lib/active_support/callbacks.rb:127:in `block in run_callbacks'
 8433c989 | /usr/share/gems/gems/audited-5.8.0/lib/audited/sweeper.rb:16:in `around'
 8433c989 | /usr/share/gems/gems/activesupport-7.0.10/lib/active_support/callbacks.rb:127:in `block in run_callbacks'
 8433c989 | /usr/share/gems/gems/activesupport-7.0.10/lib/active_support/callbacks.rb:138:in `run_callbacks'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/abstract_controller/callbacks.rb:233:in `process_action'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_controller/metal/rescue.rb:23:in `process_action'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_controller/metal/instrumentation.rb:67:in `block in process_action'
 8433c989 | /usr/share/gems/gems/activesupport-7.0.10/lib/active_support/notifications.rb:206:in `block in instrument'
 8433c989 | /usr/share/gems/gems/activesupport-7.0.10/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
 8433c989 | /usr/share/gems/gems/activesupport-7.0.10/lib/active_support/notifications.rb:206:in `instrument'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_controller/metal/instrumentation.rb:66:in `process_action'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_controller/metal/params_wrapper.rb:259:in `process_action'
 8433c989 | /usr/share/gems/gems/activerecord-7.0.10/lib/active_record/railties/controller_runtime.rb:27:in `process_action'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/abstract_controller/base.rb:151:in `process'
 8433c989 | /usr/share/gems/gems/actionview-7.0.10/lib/action_view/rendering.rb:39:in `process'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_controller/metal.rb:188:in `dispatch'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_controller/metal.rb:251:in `dispatch'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/routing/route_set.rb:32:in `serve'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/routing/mapper.rb:18:in `block in <class:Constraints>'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/routing/mapper.rb:48:in `serve'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/journey/router.rb:50:in `block in serve'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/journey/router.rb:32:in `each'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/journey/router.rb:32:in `serve'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/routing/route_set.rb:852:in `call'
 8433c989 | /usr/share/gems/gems/katello-4.21.0/lib/katello/middleware/organization_created_enforcer.rb:18:in `call'
 8433c989 | /usr/share/gems/gems/katello-4.21.0/lib/katello/middleware/event_daemon.rb:10:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/static.rb:23:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/static.rb:23:in `call'
 8433c989 | /usr/share/gems/gems/apipie-dsl-2.6.2/lib/apipie_dsl/static_dispatcher.rb:67:in `call'
 8433c989 | /usr/share/gems/gems/apipie-rails-1.5.0/lib/apipie/static_dispatcher.rb:72:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/static.rb:23:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/static.rb:23:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/static.rb:23:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/static.rb:23:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/static.rb:23:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/static.rb:23:in `call'
 8433c989 | /usr/share/foreman/lib/foreman/middleware/libvirt_connection_cleaner.rb:9:in `call'
 8433c989 | /usr/share/foreman/lib/foreman/middleware/telemetry.rb:10:in `call'
 8433c989 | /usr/share/gems/gems/apipie-rails-1.5.0/lib/apipie/middleware/checksum_in_headers.rb:27:in `call'
 8433c989 | /usr/share/gems/gems/prometheus-client-4.2.5/lib/prometheus/middleware/exporter.rb:33:in `call'
 8433c989 | /usr/share/gems/gems/rack-2.2.4/lib/rack/tempfile_reaper.rb:15:in `call'
 8433c989 | /usr/share/gems/gems/rack-2.2.4/lib/rack/etag.rb:27:in `call'
 8433c989 | /usr/share/gems/gems/rack-2.2.4/lib/rack/conditional_get.rb:27:in `call'
 8433c989 | /usr/share/gems/gems/rack-2.2.4/lib/rack/head.rb:12:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/http/permissions_policy.rb:38:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/http/content_security_policy.rb:39:in `call'
 8433c989 | /usr/share/foreman/lib/foreman/middleware/logging_context_session.rb:22:in `call'
 8433c989 | /usr/share/gems/gems/rack-2.2.4/lib/rack/session/abstract/id.rb:266:in `context'
 8433c989 | /usr/share/gems/gems/rack-2.2.4/lib/rack/session/abstract/id.rb:260:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/cookies.rb:704:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
 8433c989 | /usr/share/gems/gems/activesupport-7.0.10/lib/active_support/callbacks.rb:99:in `run_callbacks'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/callbacks.rb:26:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/debug_exceptions.rb:28:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/show_exceptions.rb:29:in `call'
 8433c989 | /usr/share/gems/gems/railties-7.0.10/lib/rails/rack/logger.rb:40:in `call_app'
 8433c989 | /usr/share/gems/gems/railties-7.0.10/lib/rails/rack/logger.rb:27:in `call'
 8433c989 | /usr/share/gems/gems/sprockets-rails-3.5.2/lib/sprockets/rails/quiet_assets.rb:17:in `call'
 8433c989 | /usr/share/foreman/lib/foreman/middleware/logging_context_request.rb:11:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/remote_ip.rb:93:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/request_id.rb:26:in `call'
 8433c989 | /usr/share/gems/gems/katello-4.21.0/lib/katello/prevent_json_parsing.rb:12:in `call'
 8433c989 | /usr/share/gems/gems/rack-2.2.4/lib/rack/method_override.rb:24:in `call'
 8433c989 | /usr/share/gems/gems/rack-2.2.4/lib/rack/runtime.rb:22:in `call'
 8433c989 | /usr/share/gems/gems/activesupport-7.0.10/lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/executor.rb:14:in `call'
 8433c989 | /usr/share/gems/gems/rack-2.2.4/lib/rack/sendfile.rb:110:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/ssl.rb:77:in `call'
 8433c989 | /usr/share/gems/gems/actionpack-7.0.10/lib/action_dispatch/middleware/host_authorization.rb:131:in `call'
 8433c989 | /usr/share/gems/gems/secure_headers-7.1.0/lib/secure_headers/middleware.rb:11:in `call'
 8433c989 | /usr/share/gems/gems/railties-7.0.10/lib/rails/engine.rb:531:in `call'
 8433c989 | /usr/share/gems/gems/railties-7.0.10/lib/rails/railtie.rb:226:in `public_send'
 8433c989 | /usr/share/gems/gems/railties-7.0.10/lib/rails/railtie.rb:226:in `method_missing'
 8433c989 | /usr/share/gems/gems/rack-2.2.4/lib/rack/urlmap.rb:74:in `block in call'
 8433c989 | /usr/share/gems/gems/rack-2.2.4/lib/rack/urlmap.rb:58:in `each'
 8433c989 | /usr/share/gems/gems/rack-2.2.4/lib/rack/urlmap.rb:58:in `call'
 8433c989 | /usr/share/gems/gems/puma-6.6.1/lib/puma/configuration.rb:279:in `call'
 8433c989 | /usr/share/gems/gems/puma-6.6.1/lib/puma/request.rb:99:in `block in handle_request'
 8433c989 | /usr/share/gems/gems/puma-6.6.1/lib/puma/thread_pool.rb:390:in `with_force_shutdown'
 8433c989 | /usr/share/gems/gems/puma-6.6.1/lib/puma/request.rb:98:in `handle_request'
 8433c989 | /usr/share/gems/gems/puma-6.6.1/lib/puma/server.rb:472:in `process_client'
 8433c989 | /usr/share/gems/gems/puma-6.6.1/lib/puma/server.rb:254:in `block in run'
 8433c989 | /usr/share/gems/gems/puma-6.6.1/lib/puma/thread_pool.rb:167:in `block in spawn_thread'
 8433c989 | /usr/share/gems/gems/logging-2.4.0/lib/logging/diagnostic_context.rb:474:in `block in create_with_logging_context'
2026-08-05T21:09:03 [I|app|8433c989]   Rendered api/v2/errors/standard_error.json.rabl within api/v2/layouts/error_layout (Duration: 1.1ms | Allocations: 311)
2026-08-05T21:09:03 [I|app|8433c989]   Rendered layout api/v2/layouts/error_layout.json.erb (Duration: 2.1ms | Allocations: 572)
2026-08-05T21:09:03 [I|app|8433c989] Completed 500 Internal Server Error in 161ms (Views: 6.5ms | ActiveRecord: 33.3ms | Allocations: 12748)

Any guidance or insight on what changed with auth_source_ldap in 3.18.x would be greatly appreciated.

As soon as I posted this, I noticed this PR: Fixes #39590 - Fix LDAP/external usergroups API by michalgritzbach · Pull Request #11131 · theforeman/foreman · GitHub
It resolves the problem for me. Is it safe to cherry-pick it? :smile:

That still remains to be seen. In the meantime, as a workaround, calling /api/auth_source_ldaps/$id and plucking the value from under the external_usergroups key should work. Not great, but if you rely on it…

1 Like

This is a great workaround and requires only a minimal change to our scripts. I’ll use this instead of the patch. Thanks!