we-promise/sure · error · Provider::Questrade::ConfigurationError
missing_api_server
missing_api_server
Error message
No api_server; authenticate first
What it means
Raised by Provider::Questrade#api_base: every data request builds its URL from @api_server (the per-session base URL Questrade returns in the token exchange), and if it is blank you get ConfigurationError(:missing_api_server). It means the client tried to call a data endpoint before a successful exchange established api_server, or the caller passed api_server: nil and never authenticated.
Source
Thrown at app/models/provider/questrade.rb:185
end
body = JSON.parse(response.body, symbolize_names: true)
@access_token = body[:access_token]
@api_server = body[:api_server]
@refresh_token = body[:refresh_token] # rotate in-memory immediately
@access_expires_at = Time.current + (body[:expires_in].to_i - ACCESS_TOKEN_SKEW).seconds
# Hand the new credentials to the caller to persist (single-use token!).
@on_token_refresh&.call(
refresh_token: @refresh_token,
api_server: @api_server,
access_token: @access_token,
expires_at: @access_expires_at
)
end
def api_base
raise ConfigurationError.new("No api_server; authenticate first", :missing_api_server) if @api_server.blank?
@api_server.end_with?("/") ? @api_server : "#{@api_server}/"
end
def auth_headers
{
"Authorization" => "Bearer #{@access_token}",
"Accept" => "application/json"
}
end
def iso(time)
time.utc.iso8601
end
def with_retries(operation_name, max_retries: MAX_RETRIES)
retries = 0
beginView on GitHub (pinned to e69894adb9)
Solutions
- Always run authentication before data calls: the public methods go through get_json -> ensure_authenticated!, so make sure nothing bypasses it (a direct get_json call in a subclass or spec will hit this).
- Persist api_server alongside the refresh token via on_token_refresh (the callback hands you api_server), and pass it back on the next construct so no exchange is needed.
- If you stub/mock in tests, stub the exchange to return an api_server or stub get_json entirely.
- Check the persisted item: blank api_server with a present refresh token means the callback did not save it — fix the persistence path.
Example fix
# before
provider = Provider::Questrade.new(refresh_token: token, api_server: nil)
provider.get_holdings(account_id: id) # api_base raises missing_api_server
# after
provider = Provider::Questrade.new(
refresh_token: token,
api_server: item.settings["api_server"], # restored from last exchange
on_token_refresh: ->(creds) { item.update_credentials!(creds) }
)
provider.list_accounts # triggers exchange which sets api_server Defensive patterns
Strategy: validation
Validate before calling
api_server = item.settings["api_server"] if api_server.blank? && item.settings["refresh_token"].blank? raise ArgumentError, "cannot reach Questrade without credentials; authenticate first" end # get_json -> ensure_authenticated! sets api_server before any data call
Try / catch
begin provider.get_holdings(account_id: id) rescue Provider::Questrade::ConfigurationError => e raise unless e.error_type == :missing_api_server provider.exchange_token! # establish api_server, then retry retry end
Prevention
- Always persist api_server together with the rotated token in on_token_refresh.
- Never call get_json from outside the public methods — they guarantee authentication order.
When it happens
Trigger: Constructing with api_server: nil and calling get_json before ensure_authenticated!/exchange_token! has run; a token exchange body missing :api_server so @api_server stays nil; a new process instance created per request but only used for data calls without re-authenticating.
Common situations: Refactor that caches a provider instance across an exchange boundary; persisted item having the refresh token but a blank api_server column; stubbing exchange in tests so @api_server is never set, then hitting a data method.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/198fb85767adc94d.
Report an issue: GitHub.