{"record":{"id":"281b96dd790b6a80","repo":"we-promise/sure","slug":"claim-failed","errorCode":"claim_failed","errorMessage":"Failed to claim access URL: #{response.code} #{response.message}","messagePattern":"Failed to claim access URL: #(.+?) #(.+?)","errorType":"exception","errorClass":"Provider::Simplefin::SimplefinError","httpStatus":null,"severity":"error","filePath":"app/models/provider/simplefin.rb","lineNumber":50,"sourceCode":"  def claim_access_url(setup_token)\n    # Decode the base64 setup token to get the claim URL\n    claim_url = Base64.decode64(setup_token)\n\n    # Use retry logic for transient network failures during token claim\n    # Claim should be fast; keep request-path latency bounded.\n    # Use self.class.post to inherit class-level SSL and timeout defaults\n    response = with_retries(\"POST /claim\", max_retries: 1, backoff: false) do\n      self.class.post(claim_url, timeout: 15)\n    end\n\n    case response.code\n    when 200\n      # The response body contains the access URL with embedded credentials\n      response.body.strip\n    when 403\n      raise SimplefinError.new(\"Setup token may be compromised, expired, or already used\", :token_compromised)\n    else\n      raise SimplefinError.new(\"Failed to claim access URL: #{response.code} #{response.message}\", :claim_failed)\n    end\n  end\n\n  def get_accounts(access_url, start_date: nil, end_date: nil, pending: nil)\n    # Build query parameters\n    query_params = {}\n\n    # SimpleFin expects Unix timestamps for dates\n    if start_date\n      start_timestamp = start_date.to_time.to_i\n      query_params[\"start-date\"] = start_timestamp.to_s\n    end\n\n    if end_date\n      end_timestamp = end_date.to_time.to_i\n      query_params[\"end-date\"] = end_timestamp.to_s\n    end\n","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/simplefin.rb#L32-L68","documentation":"Raised by Provider::Simplefin#claim_access_url when the claim POST returns any status other than 200 or 403, with error_type :claim_failed. The message embeds the HTTP status and HTTParty message. Note the claim runs with max_retries: 1 and no backoff, so network resilience here is minimal by design (claim should be fast).","triggerScenarios":"Setup token base64-decodes to something that is not a valid claim URL (404/hostname failure); SimpleFin bridge cluster down or returning 5xx; redirect/misconfigured token from a nonstandard bridge.","commonSituations":"Hand-edited or truncated base64 token decoding to garbage; SimpleFin bridge maintenance window; tokens issued by a self-hosted bridge whose URL the app cannot reach.","solutions":["Decode the token and confirm it yields a valid https claim URL before calling (Base64.decode64(token))","Check the SimpleFin bridge status page for outages","Retry with a newly generated token if the current one may be malformed","Handle 5xx claim failures with a caller-side retry schedule (the client retries only once, without backoff)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"require \"uri\"\n\ndef claim_url_from_token(setup_token)\n  decoded = Base64.decode64(setup_token.to_s)\n  uri = URI.parse(decoded)\n  uri.is_a?(URI::HTTPS) ? uri : nil\nrescue URI::InvalidURIError, ArgumentError\n  nil\nend\n\nraise ArgumentError, \"invalid setup token\" unless claim_url_from_token(setup_token)","typeGuard":"def simplefin_claim_failed?(error)\n  error.is_a?(Provider::Simplefin::SimplefinError) && error.error_type == :claim_failed\nend","tryCatchPattern":"begin\n  access_url = client.claim_access_url(setup_token)\nrescue Provider::Simplefin::SimplefinError => e\n  raise unless e.error_type == :claim_failed\n  ClaimRetryJob.perform_in(5.minutes, user.id) if e.message.match?(/\\b5\\d\\d\\b/)\nend","preventionTips":["Decode-and-validate the token to a https URL before calling claim (the client does not)","Remember the claim path retries only once without backoff — put outer resilience in the caller","Keep tokens short-lived in storage and regenerate rather than reusing old ones"],"tags":["simplefin","token-claim","setup-token","bridge","http-error"],"backgroundTag":"token-exchange-failed","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}