we-promise/sure · error · Provider::Mfapi::InvalidSecurityPriceError
No NAV data returned for scheme #{symbol}
Error message
No NAV data returned for scheme #{symbol} What it means
Raised by Provider::Mfapi#fetch_security_prices (as InvalidSecurityPriceError) when the /mf/{schemeCode}?startDate=...&endDate=... response is valid JSON but its data field is either absent (nil) or not an Array. The MFAPI NAV contract is {meta: {...}, data: [{date, nav}, ...]}, so a missing/non-array data means the payload is an error or maintenance envelope that check_api_error! did not classify (it only fires on status ERROR/FAIL). Distinct from error 341: here the payload shape itself is wrong, before any row filtering happens.
Source
Thrown at app/models/provider/mfapi.rb:114
historical_data.data.select { |p| p.date <= date }.max_by(&:date) || historical_data.data.first
end
end
def fetch_security_prices(symbol:, exchange_operating_mic: nil, start_date:, end_date:)
with_provider_response do
throttle_request
response = client.get("#{base_url}/mf/#{CGI.escape(symbol)}") do |req|
req.params["startDate"] = start_date.to_s
req.params["endDate"] = end_date.to_s
end
parsed = JSON.parse(response.body)
check_api_error!(parsed)
nav_data = parsed["data"]
if nav_data.nil? || !nav_data.is_a?(Array)
raise InvalidSecurityPriceError, "No NAV data returned for scheme #{symbol}"
end
nav_data.filter_map do |entry|
nav = entry["nav"]
date_str = entry["date"]
next if nav.nil? || nav.to_f <= 0 || date_str.blank?
# MFAPI returns dates as DD-MM-YYYY
date = Date.strptime(date_str, "%d-%m-%Y")
Price.new(
symbol: symbol,
date: date,
price: nav.to_f,
currency: "INR",
exchange_operating_mic: exchange_operating_mic
)View on GitHub (pinned to e69894adb9)
Solutions
- Capture and inspect response.body for the failing schemeCode to see which envelope MFAPI actually returned.
- Treat a missing data key as an upstream error: log it via DebugLogEntry with provider_key and retry once after backoff before raising.
- Confirm the schemeCode exists via the /mf/search endpoint first when the symbol is user-supplied.
- If MFAPI renamed the field, map the new key with parsed["data"] || parsed["nav"] fallback only after verifying upstream docs.
Example fix
# before
nav_data = parsed["data"]
if nav_data.nil? || !nav_data.is_a?(Array)
raise InvalidSecurityPriceError, "No NAV data returned for scheme #{symbol}"
end
# after
nav_data = parsed.is_a?(Hash) ? parsed["data"] : nil
if nav_data.nil? || !nav_data.is_a?(Array)
DebugLogEntry.capture("mfapi", :error, "Unexpected NAV payload for #{symbol}", metadata: { body: parsed.to_s.truncate(500) })
raise InvalidSecurityPriceError, "No NAV data returned for scheme #{symbol}"
end Defensive patterns
Strategy: try-catch
Try / catch
begin
series = provider.fetch_security_prices(symbol: code, start_date: from, end_date: to)
rescue Provider::Mfapi::InvalidSecurityPriceError => e
DebugLogEntry.capture("mfapi", :error, e.message, provider_key: "mfapi")
series = ProviderResponse.new(data: [])
end Prevention
- Log the raw payload whenever the data key is missing — envelope drift must be seen to be fixed.
- Honor the provider's throttle_request interval in bulk backfills to avoid rate-limit envelopes.
- Contract-test the /mf/{code} response shape (meta + data array) in CI.
When it happens
Trigger: MFAPI returns {"message": "..."} or {} for an overloaded/rate-limited request; a scheme that exists but returns an object without data while its status field is missing; upstream schema change renaming data; intermediate proxy returning valid-JSON error object without status.
Common situations: Hitting MFAPI's unwritten rate limits during a large portfolio backfill; MFAPI maintenance windows; using a schemeCode that triggers a non-standard response (e.g. non-numeric garbage in the URL segment, though that usually yields status ERROR); CDN edge responses.
Related errors
- Unexpected response format from search endpoint
- No NAV found for scheme #{symbol} on or before #{date}
- API error: #{parsed['message'] || parsed['status']}
- unknown
- invalid_response
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/12fed8bed69c61b4.
Report an issue: GitHub.