{"record":{"id":"dcc2db38a4cde918","repo":"opf/openproject","slug":"ldap-error-error-message","errorCode":null,"errorMessage":"LDAP-Error: %{error_message}","messagePattern":"LDAP-Error: %(.+?)","errorType":"exception","errorClass":"LdapAuthSource::Error","httpStatus":null,"severity":"error","filePath":"app/models/ldap_auth_source.rb","lineNumber":188,"sourceCode":"\n    attrs\n  rescue Net::LDAP::Error => e\n    raise LdapAuthSource::Error, \"LdapError: #{e.message}\"\n  end\n\n  # Open and return a system connection\n  def with_connection\n    yield initialize_ldap_con(account, account_password)\n  end\n\n  # test the connection to the LDAP\n  def test_connection\n    unless authenticate_dn(account, account_password)\n      raise LdapAuthSource::Error,\n            I18n.t(\"ldap_auth_sources.ldap_error\", error_message: I18n.t(\"ldap_auth_sources.ldap_auth_failed\"))\n    end\n  rescue Net::LDAP::Error => e\n    raise LdapAuthSource::Error,\n          I18n.t(\"ldap_auth_sources.ldap_error\", error_message: e.to_s)\n  end\n\n  def get_user_attributes_from_ldap_entry(entry)\n    base_attributes = {\n      dn: entry.dn,\n      ldap_auth_source_id: id\n    }\n\n    base_attributes.merge mapped_attributes(entry)\n  end\n\n  def mapped_attributes(entry)\n    %i[login firstname lastname mail admin].each_with_object({}) do |key, hash|\n      ldap_attribute = send(:\"attr_#{key}\")\n      next if ldap_attribute.blank?\n\n      val = LdapAuthSource.get_attr(entry, ldap_attribute)","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/opf/openproject/blob/d9742c43f3424c34b63550f8c03f201fe5c3040c/app/models/ldap_auth_source.rb#L170-L206","documentation":"This variant of the LDAP test error comes from the rescue Net::LDAP::Error branch in LdapAuthSource#test_connection: the raised LdapAuthSource::Error interpolates the underlying exception into ldap_error ('%{error_message}'). Unlike the auth-failed variant, the failure happened while establishing the connection or during TLS — before any bind credential mattered.","triggerScenarios":"Testing an LDAP source with an unreachable host, DNS failure, wrong port (e.g. 636 without LDAPS enabled, or 389 against a TLS-only server), firewall drop, or a failing certificate handshake (untrusted/self-signed CA).","commonSituations":"Host/port typos in the auth source; LDAPS/StartTLS mismatch; self-signed certificates without a trusted CA on the OpenProject host; firewall or VPN blocking the app server but not an admin's laptop.","solutions":["Read the interpolated error message — Net::LDAP names the concrete cause (connection refused, timeout, certificate verify failed).","Fix connectivity: verify host/port with nc -zv host 636 and confirm the LDAPS toggle matches the port.","For TLS/certificate errors, trust the LDAP server's CA on the application host (or point net-ldap at the CA bundle), then retest."],"exampleFix":"# before\nLdapAuthSource.new(host: 'ldap.example.com', port: 636, ldaps: false)\n\n# after\nLdapAuthSource.new(host: 'ldap.example.com', port: 636, ldaps: true)","handlingStrategy":"try-catch","validationCode":"require 'resolv'\nResolv::DNS.open { |dns| dns.getaddress(host) } # fail fast on DNS\nrequire 'socket'\nSocket.tcp(host, port, connect_timeout: 5)     # fail fast on reachability","typeGuard":null,"tryCatchPattern":"begin\n  ldap_auth_source.test_connection\nrescue LdapAuthSource::Error => e\n  retry_once_after_network_change if e.message =~ /connection refused|timeout|certificate/\n  raise\nend","preventionTips":["Pre-check host/port reachability (Socket.tcp) and TLS (OpenSSL connect) before the LDAP test.","Keep the LDAPS flag and port consistent (636 + ldaps, 389 + start_tls).","Trust the LDAP server's CA on the app host; don't disable verification as a fix."],"tags":["ldap","connection-error","tls","network","configuration"],"backgroundTag":"ldap-connection-error","analyzedSha":"d9742c43f3424c34b63550f8c03f201fe5c3040c","analyzedAt":"2026-08-21T14:40:06.829Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}