we-promise/sure · error · Provider::Mfapi::InvalidSecurityPriceError

No NAV found for scheme #{symbol} on or before #{date}

Error message

No NAV found for scheme #{symbol} on or before #{date}

What it means

Raised by Provider::Mfapi#fetch_security_price (an InvalidSecurityPriceError subclass) when a 7-day lookback window (date - 7.days .. date) of NAV entries comes back with zero usable rows. MFAPI publishes one NAV per Indian business day, so this means the window contained no NAV records at all — not merely that the exact date was missing (the code already falls back to the closest previous date or first record). The upstream fetch must have succeeded (its error is re-raised first), so this is a data-availability failure, not a transport failure.

Source

Thrown at app/models/provider/mfapi.rb:93

      SecurityInfo.new(
        symbol: symbol,
        name: meta["scheme_name"],
        links: nil,
        logo_url: nil,
        description: [ meta["fund_house"], meta["scheme_category"] ].compact.join(" - "),
        kind: "mutual fund",
        exchange_operating_mic: exchange_operating_mic
      )
    end
  end

  def fetch_security_price(symbol:, exchange_operating_mic: nil, date:)
    with_provider_response do
      historical_data = fetch_security_prices(symbol:, exchange_operating_mic:, start_date: date - 7.days, end_date: date)

      raise historical_data.error if historical_data.error.present?
      raise InvalidSecurityPriceError, "No NAV found for scheme #{symbol} on or before #{date}" if historical_data.data.blank?

      # Find exact date or closest previous
      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"]

View on GitHub (pinned to e69894adb9)

Solutions

  1. Verify the schemeCode is a real MFAPI scheme: hit https://api.mfapi.in/mf/{schemeCode} directly and confirm the data array is non-empty for your window.
  2. Widen the lookback window (e.g. date - 30.days) so inception gaps and publication holidays still resolve to the nearest prior NAV.
  3. Clamp requested dates to on/after the scheme's first NAV (meta scheme_start_date from the /mf/{code} response) before calling.
  4. Catch InvalidSecurityPriceError at the sync layer and mark the price as missing for that date instead of failing the whole sync.

Example fix

# before
historical_data = fetch_security_prices(symbol:, exchange_operating_mic:, start_date: date - 7.days, end_date: date)

# after
historical_data = fetch_security_prices(symbol:, exchange_operating_mic:, start_date: date - 30.days, end_date: date)
Defensive patterns

Strategy: try-catch

Validate before calling

raise ArgumentError, "date must be on/after scheme inception" if date < scheme.inception_date if scheme.respond_to?(:inception_date)

Try / catch

begin
  nav = provider.fetch_security_price(symbol: code, date: date)
rescue Provider::Mfapi::InvalidSecurityPriceError
  nav = nil # carry forward last known NAV / skip this date
end

Prevention

When it happens

Trigger: Requesting a date earlier than the fund's inception (e.g. a 2023 date for a 2025 NFO); querying a scheme code whose data array was returned but every entry was filtered out by filter_map (nav nil, nav <= 0, blank DD-MM-YYYY date); a date range falling entirely in a long NAV-publication gap; wrong schemeCode that MFAPI still answers with an empty data array.

Common situations: Backfilling portfolio history for newly launched schemes; user typed an ISIN or name instead of the numeric schemeCode; stale symbol saved before the scheme merged/wound up; requesting today's date before the AMFI NAV for today is published and the previous week's window somehow returns empty.

Related errors


AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21). Data as JSON: /api/errors/724d1e986aaa8c8d. Report an issue: GitHub.