opf/openproject · error · Import::JiraClient::ApiError

Jira API returned error status %{status}

Error message

Jira API returned error status %{status}

What it means

This is Import::JiraClient#handle_response's generic branch: a non-2xx status that has no dedicated translation key falls back to admin.jira.client.api_error ('Jira API returned error status %{status}'). The raised ApiError still carries status and response_body, so the real cause must be read from those fields. Typical statuses behind it: 403 (missing permission), 404 (wrong base URL/context path), 500/502/503 (Jira-side failure).

Source

Thrown at app/services/import/jira_client.rb:309

        params:,
        http_options: HTTP_OPTIONS
      )
    rescue SsrfFilter::PrivateIPAddress
      raise SsrfError, I18n.t("admin.jira.client.ssrf_blocked")
    rescue SsrfFilter::Error, SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH => e
      raise ConnectionError, I18n.t("admin.jira.client.connection_error", message: e.message)
    rescue OpenSSL::SSL::SSLError => e
      raise ConnectionError, I18n.t("admin.jira.client.ssl_error", message: e.message)
    rescue Timeout::Error => e
      raise ConnectionError, I18n.t("admin.jira.client.connection_timeout", message: e.message)
    end

    def handle_response(response)
      status = response.code.to_i
      if response.is_a?(Net::HTTPSuccess)
        parse_json(response)
      else
        raise ApiError.new(
          I18n.t("admin.jira.client.#{status}_error", status:, default: :"admin.jira.client.api_error"),
          status:,
          response_body: response.body.to_s
        )
      end
    end

    def parse_json(response)
      JSON.parse(response.body)
    rescue JSON::ParserError => e
      raise ParseError, I18n.t("admin.jira.client.parse_error", message: e.message)
    end
  end
end

View on GitHub (pinned to d9742c43f3)

Solutions

  1. Inspect the exception's status and response_body (or the logged job output) — Jira's JSON error messages identify the exact problem.
  2. For 404: fix the base URL in the Jira settings (include the context path if Jira is not at root) and re-test the connection.
  3. For 403: grant the token owner browse/admin permission on the projects being imported.
  4. For 5xx: check Jira health/logs, then retry the import run once Jira is stable.

Example fix

# before
rescue Import::JiraClient::ApiError => e
  Rails.logger.error e.message

# after
rescue Import::JiraClient::ApiError => e
  Rails.logger.error "Jira #{e.status}: #{e.response_body}"
Defensive patterns

Strategy: try-catch

Try / catch

begin
  client.get(path)
rescue Import::JiraClient::ApiError => e
  Rails.logger.error "Jira #{e.status}: #{e.response_body}"
  raise if [500, 502, 503].include?(e.status) # retryable upstream failures
end

Prevention

When it happens

Trigger: Any JiraClient call returning e.g. 404 because the configured URL misses the context path (jira.example.com instead of jira.example.com/jira), 403 because the token lacks the needed project permission, or 5xx during Jira maintenance — none of which have status-specific locale keys.

Common situations: Wrong or half-configured Jira base URL (404 on every endpoint); token owner can authenticate but cannot browse the projects being imported (403); Jira restarted/out of memory mid-import (503); reverse proxy in front of Jira returning its own error codes.

Related errors


AI-assisted analysis of opf/openproject@d9742c43f3 (2026-08-21). Data as JSON: /api/errors/e6e7b9073bad39b0. Report an issue: GitHub.