{"record":{"id":"8fe12403c660051a","repo":"we-promise/sure","slug":"realie-did-not-return-a-valuation-for-this-propert","errorCode":null,"errorMessage":"Realie did not return a valuation for this property.","messagePattern":"Realie did not return a valuation for this property\\.","errorType":"exception","errorClass":"Provider::Realie::Error","httpStatus":null,"severity":"warning","filePath":"app/models/provider/realie.rb","lineNumber":74,"sourceCode":"        req.params[\"state\"] = region.to_s.strip.upcase\n      end\n\n      parsed = JSON.parse(response.body)\n      records = parsed[\"property\"]\n      records = [ records ] unless records.is_a?(Array)\n      records = records.reject(&:blank?)\n      raise Error.new(I18n.t(\"providers.realie.errors.no_property\")) if records.empty?\n\n      # A street+state query can return several candidates across different\n      # cities; pick the first one consistent with the entered city/ZIP.\n      record = records.find { |candidate| location_match?(candidate, locality: locality, postal_code: postal_code) }\n      raise Error.new(I18n.t(\"providers.realie.errors.location_mismatch\")) if record.nil?\n\n      # Realie returns modelValue: 0 when it couldn't produce an AVM\n      # estimate, so zero counts as absent and falls back to the assessed\n      # total market value.\n      valuation = [ record[\"modelValue\"], record[\"totalMarketValue\"] ].find { |value| value.present? && value.to_d.positive? }\n      raise Error.new(I18n.t(\"providers.realie.errors.no_valuation\")) if valuation.nil?\n\n      PropertyValuation.new(\n        valuation: BigDecimal(valuation.to_s),\n        currency: \"USD\",\n        property_type: subtype_for_use_code(record[\"useCode\"]),\n        year_built: record[\"yearBuilt\"],\n        area_value: record[\"buildingArea\"],\n        area_unit: \"sqft\"\n      )\n    end\n  end\n\n  private\n    attr_reader :api_key\n\n    # The address lookup matches on street + state only (filtering by city\n    # additionally requires a county, which isn't collected), so a common\n    # street name can resolve to properties in other cities. A candidate","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/realie.rb#L56-L92","documentation":"Raised in Provider::Realie#fetch_property_valuation after a record matched the address: neither record[\"modelValue\"] nor record[\"totalMarketValue\"] was present AND positive. Realie deliberately returns modelValue: 0 when its AVM cannot produce an estimate, so zero counts as absent and the assessed totalMarketValue is the fallback; when both are 0/blank the provider gives up with the I18n no_valuation message.","triggerScenarios":"A matched property whose AVM model has no estimate (0 modelValue) AND no assessed totalMarketValue in the county data (new construction, recently split parcels, counties with sparse assessment feeds); records where both fields are null strings; values returned as negative or non-numeric strings that to_d evaluates to 0.","commonSituations":"Newly built homes ahead of the first tax assessment; rural counties with minimal data; older records where only land value is assessed and market fields are empty; users expecting a valuation where public data simply does not have one yet.","solutions":["Treat as expected data absence: fall back to another valuation provider or prompt the user to enter a manual valuation.","Retry after the next county assessment cycle if the property is new (no code change helps until data exists).","Inspect the raw record once (log record[\"modelValue\"], record[\"totalMarketValue\"]) to confirm both are truly 0/blank rather than formatted oddly (e.g. '$450,000' or '450K' strings would to_d to 0 — if seen, normalize strings before the check in your own wrapper).","Gate the 'estimated value' UI affordance on valuation presence so users are not promised a number the county cannot supply."],"exampleFix":"# before\nvaluation = realie.fetch_property_valuation(line1:, locality:, region:, postal_code:)\n\n# after\nbegin\n  valuation = realie.fetch_property_valuation(line1:, locality:, region:, postal_code:)\nrescue Provider::Realie::Error => e\n  raise unless e.message == I18n.t(\"providers.realie.errors.no_valuation\")\n  valuation = rentcast.fetch_property_valuation(line1:, locality:, region:, postal_code:) # alternate AVM\nend","handlingStrategy":"fallback","validationCode":"# cheap pre-check on any locally cached record copy (the live check lives in the provider)\nhas_value = ->(v) { v.present? && v.to_d.positive? }\n# nothing to validate pre-call for a first lookup — the data lives server-side","typeGuard":null,"tryCatchPattern":"begin\n  valuation = realie.fetch_property_valuation(line1:, locality:, region:, postal_code:)\nrescue Provider::Realie::Error => e\n  raise unless e.message == I18n.t(\"providers.realie.errors.no_valuation\")\n  valuation = rentcast.fetch_property_valuation(line1:, locality:, region:, postal_code:)\nend","preventionTips":["Design the valuation flow as provider-chained: Realie absent value -> alternate AVM -> manual entry prompt.","Do not promise an AVM number in the UI until a provider returns one.","If string-formatted values ('$450,000') ever appear in feeds, normalize before the positive? check in your wrapper."],"tags":["realie","property-valuation","missing-data","avm","zero-value"],"backgroundTag":"missing-field-in-response","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}