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

Jira API returned a 401 error. Your authentication token may

Error message

Jira API returned a 401 error. Your authentication token may have expired or lack the required permissions. Please ensure the token belongs to a Jira administrator.

What it means

Import::JiraClient#handle_response turns every non-2xx HTTP response into an ApiError whose message comes from the locale key admin.jira.client.401_error. A 401 from Jira means the Bearer token was rejected: expired, revoked/regenerated, wrong value, or the token owner is not a Jira administrator as required by the importer.

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. Create a fresh API token in Jira for an administrator account, update it in Admin → Import → Jira settings, save and run the test connection.
  2. Confirm the token owner actually holds Jira administrator permission (the importer calls /rest/api/2/mypermissions which requires it).
  3. If the error appears mid-run after working before, the token was likely revoked/rotated — re-enter it and restart the import run.

Example fix

# before
begin
  client.mypermissions
rescue Import::JiraClient::ApiError => e
  puts e.message
end

# after
begin
  client.mypermissions
rescue Import::JiraClient::ApiError => e
  if e.status == 401
    raise 'Re-enter the Jira API token (expired or revoked) in admin settings'
  end
  raise
end
Defensive patterns

Strategy: try-catch

Try / catch

begin
  client.mypermissions
rescue Import::JiraClient::ApiError => e
  raise CredentialsExpired, 're-enter Jira API token' if e.status == 401
  raise
end

Prevention

When it happens

Trigger: Any JiraClient request (mypermissions, project/issue fetching during a run, or the admin 'test connection') after the API token was revoked or regenerated in Jira, or after the owning Jira user lost admin rights.

Common situations: Atlassian API tokens expire or get rotated; someone regenerated the token in Jira while an import run was queued; token pasted with surrounding whitespace; the settings were saved with an empty token field so a stale/blank header is sent.

Understand the failure class

Related errors


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