{"record":{"id":"0aaa510f1681f845","repo":"opf/openproject","slug":"ssl-error-connecting-to-jira-server-message","errorCode":null,"errorMessage":"SSL error connecting to Jira server: %{message}","messagePattern":"SSL error connecting to Jira server: %(.+?)","errorType":"exception","errorClass":"Import::JiraClient::ConnectionError","httpStatus":null,"severity":"error","filePath":"app/services/import/jira_client.rb","lineNumber":273,"sourceCode":"        case response\n        when Net::HTTPSuccess\n          tempfile = Tempfile.create(filename, binmode: true)\n          response.read_body do |chunk|\n            tempfile.write chunk\n          end\n          yield tempfile\n        else\n          status = response.code.to_i\n          raise ApiError.new(I18n.t(\"admin.jira.client.api_error\", status:), status:, response_body: response.body)\n        end\n      end\n      nil\n    rescue SsrfFilter::PrivateIPAddress\n      raise SsrfError, I18n.t(\"admin.jira.client.ssrf_blocked\")\n    rescue SsrfFilter::Error => e\n      raise ConnectionError, I18n.t(\"admin.jira.client.connection_error\", message: e.message)\n    rescue OpenSSL::SSL::SSLError => e\n      raise ConnectionError, I18n.t(\"admin.jira.client.ssl_error\", message: e.message)\n    rescue Timeout::Error => e\n      raise ConnectionError, I18n.t(\"admin.jira.client.connection_timeout\", message: e.message)\n    ensure\n      File.unlink(tempfile) if tempfile\n    end\n\n    private\n\n    def get(path, params: {})\n      response = get_response(path, params:)\n      handle_response(response)\n    end\n\n    def get_response(path, params: {})\n      OpenProject::SsrfProtection.get(\n        \"#{@url}#{path}\",\n        headers: @headers,\n        params:,","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/opf/openproject/blob/d9742c43f3424c34b63550f8c03f201fe5c3040c/app/services/import/jira_client.rb#L255-L291","documentation":"During download_attachment, OpenSSL::SSL::SSLError from the TLS handshake with the attachment host is wrapped into Import::JiraClient::ConnectionError with this message. Net::HTTP raises it when certificate verification fails (self-signed/untrusted CA, incomplete chain, hostname mismatch, expired certificate) or when TLS negotiation itself breaks; the OpenSSL detail stays in %{message}.","triggerScenarios":"client.download_attachment fetching an https attachment URL where the server presents a self-signed or internal-CA certificate, is missing intermediate certificates, has a CN/SAN not matching the host, has an expired certificate, or only supports TLS versions the client rejects.","commonSituations":"Self-hosted Jira behind a reverse proxy with an internal PKI certificate not trusted by the OpenProject container's CA store; admins renewing certs but forgetting intermediates; lab environments using self-signed certs; cert renewed but proxy still serving the old one.","solutions":["Inspect the certificate chain from the OpenProject host: openssl s_client -connect jira.host:443 -servername jira.host </dev/null and check the verify result","Fix the server side first: complete chain (leaf + intermediates), hostname matching, certificate not expired","For internal CAs, add the CA certificate to the OpenProject container/system trust store (Debian: copy to /usr/local/share/ca-certificates/ and run update-ca-certificates; also set NODE_EXTRA_CA_CERTS for Node-based tooling)","Never work around it by disabling certificate verification — that removes the SSRF/TLS protections this client is built around"],"exampleFix":"# before — Jira uses an internal CA; downloads fail with\n#   SSL error connecting to Jira server: ... certificate verify failed\n\n# after — trust the internal CA inside the OpenProject image\n# Dockerfile:\n#   COPY jira-internal-ca.crt /usr/local/share/ca-certificates/\n#   RUN update-ca-certificates\n# docker-compose.yml (for Node-based parts of the stack):\nenvironment:\n  NODE_EXTRA_CA_CERTS: /usr/local/share/ca-certificates/jira-internal.crt","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"begin\n  client.download_attachment(content_url, filename) { |tf| attach(tf) }\nrescue Import::JiraClient::ConnectionError => e\n  if e.message.start_with?(\"SSL error\")\n    report_cert_problem(host: URI.parse(content_url).host, detail: e.message)\n  end\n  raise\nend","preventionTips":["Manage the internal CA in the OpenProject image as configuration (COPY + update-ca-certificates), not ad-hoc","Monitor certificate expiry on the Jira/proxy side so renewals happen before imports fail","Run openssl s_client against the Jira host as part of environment bring-up checks"],"tags":["jira","ssl","tls","certificate","network","import","attachments"],"backgroundTag":"ssl-certificate-verification-failed","analyzedSha":"d9742c43f3424c34b63550f8c03f201fe5c3040c","analyzedAt":"2026-08-21T14:40:06.829Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}