{"record":{"id":"0db36c9c25fd903a","repo":"opf/openproject","slug":"invalid-api-token-please-check-your-credentials-i","errorCode":null,"errorMessage":"Invalid API token. Please check your credentials in the configuration.","messagePattern":"Invalid API token\\. Please check your credentials in the configuration\\.","errorType":"exception","errorClass":"Import::JiraClient::ApiError","httpStatus":null,"severity":"error","filePath":"app/services/import/jira_client.rb","lineNumber":57,"sourceCode":"    class ParseError < Error; end\n\n    class ApiError < Error\n      attr_reader :status, :response_body\n\n      def initialize(message, status: nil, response_body: nil)\n        super(message)\n        @status = status\n        @response_body = response_body\n      end\n    end\n\n    HTTP_OPTIONS = {\n      open_timeout: 30,\n      read_timeout: 30\n    }.freeze\n\n    def initialize(url:, personal_access_token:)\n      raise ApiError.new(I18n.t(:\"admin.jira.test.token_error\")) if personal_access_token.nil?\n\n      @url = url.chomp(\"/\")\n      @headers = {\n        \"Accept\" => \"application/json\",\n        \"Authorization\" => \"Bearer #{personal_access_token}\"\n      }\n    end\n\n    def mypermissions\n      get(\"/rest/api/2/mypermissions\")\n    end\n\n    def index_condition_summary\n      get(\"/rest/api/2/index/summary\")\n    end\n\n    def server_info\n      get(\"/rest/api/2/serverInfo\")","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/opf/openproject/blob/d9742c43f3424c34b63550f8c03f201fe5c3040c/app/services/import/jira_client.rb#L39-L75","documentation":"Import::JiraClient#initialize requires a personal_access_token because every request sends an 'Authorization: Bearer <token>' header. If the token argument is nil it immediately raises ApiError with the 'admin.jira.test.token_error' message — before any network I/O. This is the Jira importer's configuration entry check.","triggerScenarios":"Instantiating Import::JiraClient.new(url: ..., personal_access_token: nil). In the app this happens when the admin Jira import settings were saved without re-entering the token, so the controller passes nil through to the client.","commonSituations":"Re-saving the Jira settings form: password/token inputs are rendered blank after load (standard Rails security behavior) and if left empty the stored token is not resubmitted, yielding nil; automation scripts that read the token from an unset ENV var; secret stripped between requests.","solutions":["Open Admin → Import → Jira settings, re-enter the API token, save, then use the test-connection action to verify.","If you build the client programmatically, load the token from your credential store/ENV before constructing and fail fast with a clear message if missing.","Confirm the form actually posts the token parameter (check logs/params) after upgrading the admin UI."],"exampleFix":"# before\nclient = Import::JiraClient.new(url: url, personal_access_token: params[:token])\n\n# after\ntoken = params[:token].presence or raise ArgumentError, 'Jira API token missing'\nclient = Import::JiraClient.new(url: url, personal_access_token: token)","handlingStrategy":"validation","validationCode":"raise ArgumentError, 'Jira API token missing' if token.nil?","typeGuard":null,"tryCatchPattern":"begin\n  Import::JiraClient.new(url:, personal_access_token: token)\nrescue Import::JiraClient::ApiError\n  prompt_for_token_reentry\nend","preventionTips":["Preflight-check token presence in the settings controller so the user gets a form error, not a raised ApiError.","Store the token in the credential store and read it at call time instead of round-tripping it through form params.","After every save of Jira settings, run the built-in test connection to fail fast."],"tags":["jira-import","authentication","configuration","api-token"],"backgroundTag":"missing-api-credentials","analyzedSha":"d9742c43f3424c34b63550f8c03f201fe5c3040c","analyzedAt":"2026-08-21T14:40:06.829Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}