opf/openproject · error · Import::JiraClient::ParseError
Failed to parse Jira API response: %{message}
Error message
Failed to parse Jira API response: %{message} What it means
handle_response parses every 2xx body with JSON.parse; a JSON::ParserError is re-raised as Import::JiraClient::ParseError with this message. It means the HTTP request itself succeeded but the body is not JSON — almost always an HTML page (SSO login form, proxy error page) or an empty body arriving with a 200 status.
Source
Thrown at app/services/import/jira_client.rb:320
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
- Verify the base URL directly: curl -H 'Authorization: Bearer <token>' https://jira.example.com/rest/api/2/serverInfo must return JSON
- If SSO fronts Jira, configure it to bypass authentication for /rest/api/* (e.g. basic auth or anonymous REST access) so API calls are not redirected to an HTML login
- Inspect %{message}: JSON::ParserError includes the offending text/offset — '<html' fragments confirm an interceptor page
- Correct the saved URL to the bare Jira base URL and re-test the connection from the import settings
Example fix
# before — import settings URL points at an HTML page # Jira URL: https://jira.example.com/login # → GET /rest/api/2/serverInfo returns login HTML → ParseError # after # Jira URL: https://jira.example.com # curl -H "Authorization: Bearer $TOKEN" \ # https://jira.example.com/rest/api/2/serverInfo # returns JSON
Defensive patterns
Strategy: try-catch
Validate before calling
# smoke-test that the configured base URL speaks JSON before importing
resp = OpenProject::SsrfProtection.get("#{jira_url}/rest/api/2/serverInfo",
headers: { "Authorization" => "Bearer #{token}" })
abort "base URL does not serve the Jira REST API" unless resp.is_a?(Net::HTTPSuccess) && resp["Content-Type"].to_s.include?("application/json") Try / catch
begin
data = client.issues(jql: "project = X")
rescue Import::JiraClient::ParseError => e
# 2xx + non-JSON body: almost always an SSO login/proxy page in front of Jira
Rails.logger.error("Jira returned non-JSON (SSO/proxy interceptor?): #{e.message}")
raise
end Prevention
- Always configure the bare Jira base URL; never a login or portal path
- Exempt /rest/api/* from web SSO in front of Jira (basic/API-token auth path)
- Add a serverInfo JSON smoke test to import runbooks to catch interceptor pages early
When it happens
Trigger: Any Import::JiraClient API call where @url points at a non-Jira page (e.g. https://jira.example.com/login so /rest/api/2/... returns the login HTML), an SSO/SAML layer in front of Jira redirects REST calls to an HTML login page, an intermediary (proxy, captive portal, WAF) returns an HTML block page with 200, or the URL scheme/host is wrong so the response comes from an unrelated server.
Common situations: Saving the Jira login page URL instead of the base URL in the import settings; SAML/OIDC web SSO in front of Jira that does not exempt /rest/api; reverse proxies serving custom error pages; typo'd domains resolving to a parked page; API token invalid so an HTML error page is returned instead of JSON.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Connection blocked: the Jira host resolves to a private IP a
- Failed to connect to Jira server: %{message}
- SSL error connecting to Jira server: %{message}
- Connection to Jira server timed out: %{message}
- Filter must be a JSON object, got #{filter.class}
AI-assisted analysis of opf/openproject@d9742c43f3 (2026-08-21).
Data as JSON: /api/errors/b31303c44a7d87c5.
Report an issue: GitHub.