adwork

adwork

Hi friends, I’m totally newbie, but since I see this error I can’t figure out what if causing this error.

This error triggered on a recurrent cron task which checks db for flag then script gets token to fetch data from google maps API.

Some tokens are going well, and script successfully fetched and stored data in DB, some with such error fails and stops script. Error stays the same until i delete unprocessible data.

The only tokens are changing and used to fetch data from google maps api.

To stop this error I have to go do db and delete unwanted data which can’t be processed due unknown (for me) issue.

Where to go to check the initial reason why this failures appear?

2022-10-20 23:30:01.455 [error] Handle geo point error - %BadMapError{term: nil}, geo - %Schema.Geo{__meta__: #Ecto.Schema.Metadata<:loaded, "geos">, ancestry: nil, ancestry_depth: 0, awards: #Ecto.Association.NotLoaded<association :awards is not loaded>, companies: #Ecto.Association.NotLoaded<association :companies is not loaded>, country_info: #Ecto.Association.NotLoaded<association :country_info is not loaded>, country_info_id: nil, created_at: ~N[2022-10-20 21:15:44.996481], full_name: nil, groups: #Ecto.Association.NotLoaded<association :groups is not loaded>, id: "18739c62-a8f5-4528-ad27-5610d30be8e4", kind: "latlng", latitude: 36.627206160762825, legacy_id: 3058, longitude: 31.76591573513031, name: nil, state: "draft", translations: nil, units: #Ecto.Association.NotLoaded<association :units is not loaded>, updated_at: ~N[2022-10-20 21:15:44.996481]}

the db record of an affecting entry is this

and the kind is a flag and latitude+longitude (geopoint) is the token to fetch data

After the script is rightly finished, it fills changes the flag to type localities fetched from g.api data, and is translations and puts in a translations jsonb with fetched translations for different langs.

Firstly script finds the country associated with geopoint, then checks if same data collected earlier and deletes this entry if duplicate found, then updates the id in related tables to that one which is already in db.

If no dups found it fetches data from google map API and builds multiple records, yet also checks for dups before creation, then fills the ancestry so keep the logic of google API in our proxy geo db where we store different languages needed to show the data w/o need to fetch every time google api.

part of schema in fetching script


  1 defmodule Mix.Tasks.Geos.CompleteAncestry do

  2   use Mix.Task

  3   import Ecto.Query, only: [from: 2]
  4   require Logger
  5   require IEx
  6
  7   @api_key "APITOKEN"
  8   @domain "https://maps.googleapis.com/maps/api/geocode/json"
  9   @localities [
 10     %{external_name: "country", name: "country"},
 11     %{external_name: "administrative_area_level_1", name: "division"},
 12     %{external_name: "administrative_area_level_2", name: "region"},
 13     %{external_name: "administrative_area_level_3", name: "subregion"},
 14     %{external_name: "administrative_area_level_4", name: "settlement"},
 15     %{external_name: "administrative_area_level_5", name: "village"},
 16     %{external_name: "locality", name: "city"},
 17     %{external_name: "sublocality_level_1", name: "district"},
 18     %{external_name: "sublocality_level_2", name: "locality"},
 19     %{external_name: "sublocality_level_3", name: "commune"},
 20     %{external_name: "sublocality_level_4", name: "commune1"},
 21     %{external_name: "sublocality_level_5", name: "commune2"},
 22     %{external_name: "establishment", name: "establishment"},
 23     %{external_name: "street_address", name: "street_address"},
 24     %{external_name: "neighborhood", name: "neighborhood"}
 25   ]
 26
 27   def run(args) do
 28     Application.ensure_all_started(:platform)
 29     time = DateTime.from_unix!(DateTime.to_unix(Timex.now()) - 5 * 60)
 30     from_time = DateTime.from_unix!(DateTime.to_unix(Timex.now()) - 15 * 60)
 31     Logger.info("Start complete ancestry time last - #{time}")
 32 # https://developers.google.com/maps/faq#languagesupport
 33 # https://developers.google.com/maps/documentation/geocoding/requests-geocoding#language-param
 34 # we may hit usage limits on number multiplied by locales > 5 https://developers.google.com/maps/faq?hl=en#usage-limits
 35 # 50 QPS is a limit, at max we fetch for 14th languages what seems to be 14 QPS
 36     Enum.each(get_points(args, time, from_time), fn record ->
 37       try do
 38         en = request_by_point(record, "en")
 39         de = request_by_point(record, "de")

[cutted]

 52         handle_localities(%{en: en, de: de, sv: sv, fi: fi, da: da, nl: nl, fr: fr, it: it, es: es, pt: pt, ru: ru, bg: bg, el: el, tr: tr}, record)
 53       rescue
 54         e ->
 55           Logger.error("Handle geo point error - #{inspect(e)}, geo - #{inspect(record)}")
 56       end
 57     end)
 58   end
 59
 60   def get_points(args, time, from_time) do
 61     cond do
 62       is_binary(args) && args == "old" -> Schema.Geo.get_old_by_latlng(time, from_time)
 63       true -> Schema.Geo.get_last_by_latlng(time)
 64     end
 65   end

[cutted]


123   def update_last_geo(record, point, country_info_id) do

124     cond do
125       point && point.geo && !point.exist ->
126         # if point geo not exist in database, update geo and delete last point
127         record
128         |> Schema.Geo.changeset(%{
129           kind: point.geo.kind,
130           state: point.geo.state,
131           ancestry_depth: point.geo.ancestry_depth,
132           ancestry: point.geo.ancestry,
133           name: point.geo.name,
134           full_name: point.geo.full_name,
135           country_info_id: country_info_id,
136           translations: point.geo.translations
137         })
138         |> Platform.Repo.update!()
139
140         update_geom(record)
141
142         Logger.info("Deleted temporary geo - #{inspect(point.geo)}")
143         point.geo |> Platform.Repo.delete()
144
145       point && point.geo && point.exist ->
146         #  if point geo exist in database, update all points in Units, Groups, CompanyOffices
147         update_relations(record.id, point.geo)
148
149         Logger.info("Deleted exist geo - #{inspect(record)}")
150         record |> Platform.Repo.delete()
151
152       true ->
153         Logger.info("Bad data for geo #{inspect(record)}")
154     end
155   end

[cutted]

212    cond do
213       geo ->
214         {geo, true}
215
216       true ->
217         country_info = List.first(ancestries).country_info
218         geo =
219           %Schema.Geo{}
220           |> Schema.Geo.changeset(%{
221             kind: kind,
222             state: state,
223             latitude: location["lat"],
224             longitude: location["lng"],
225             ancestry_depth: length(ancestries),
226             ancestry: Enum.map_join(ancestries, "/", & &1.id),
227             name: name,
228             full_name: full_name,
229             country_info_id: (if country_info, do: country_info.id, else: nil),
230             translations: %{
231               en: %{name: name, fullname: full_name},
232               de: %{
233                 name: build_name(result.de),
234                 fullname: build_full_name(ancestries, build_name(result.de), :de)
283                 },
[cutted]
284             }
285           })
286           |> Platform.Repo.insert!()
287
288         update_geom(geo)
289         {geo, false}
290     end
291   end

[cutted]

Showing Posts 1 to 5

al2o3cr

al2o3cr

The error is happening in here, someplace, based on the message - the displayed BadMapError indicates that something passed nil where a Map was expected.

Consider adding additional output to that rescue to see the stacktrace:

rescue
  e ->
    Logger.error("etc etc etc etc\n#{Exception.format(:error, e, __STACKTRACE__)}")
adwork

adwork OP

Going to check.

adwork

adwork OP

I got this, but didn’t get it
When I change flagged record latitude/longitude to another one, same passes well.

2022-10-21 00:40:01.431 [error] My BadMapError
** (BadMapError) expected a map, got: nil
    (elixir) lib/map.ex:437: Map.get(nil, :name, nil)
    (platform) lib/platform/core/helpers/base.ex:21: Helpers.Base.get_in/2
    (elixir) lib/enum.ex:1314: Enum."-map/2-lists^map/1-0-"/2
    (platform) lib/mix/tasks/geos/complete_ancestry.ex:299: Mix.Tasks.Geos.CompleteAncestry.build_full_name/3
    (platform) lib/mix/tasks/geos/complete_ancestry.ex:239: Mix.Tasks.Geos.CompleteAncestry.find_or_create_geos/3
    (platform) lib/mix/tasks/geos/complete_ancestry.ex:98: anonymous fn/3 in Mix.Tasks.Geos.CompleteAncestry.handle_localities/2
    (elixir) lib/enum.ex:1925: Enum."-reduce/3-lists^foldl/2-0-"/3
    (platform) lib/mix/tasks/geos/complete_ancestry.ex:80: Mix.Tasks.Geos.CompleteAncestry.handle_localities/2

as i see in 21’st line

    (platform) lib/platform/core/helpers/base.ex:21: Helpers.Base.get_in/2

there is

  1 defmodule Helpers.Base do
  2   @moduledoc false
  3   def to_int(value) do
  4     case :string.to_integer(value) do
  5       {:error, _} -> value
  6       {int, _} -> int
  7     end
  8   end
  9
 10   @doc """
 11   Convert any type to string
 12   """
 13   def to_str(value) when is_atom(value), do: Atom.to_string(value)
 14   def to_str(value), do: inspect(value)
 15
 16   def to_negative(value), do: -1 * value
 17
 18   def get_in(object, list) do
 19     [source_column | path] = list
 20
 21     new_value = Map.get(object, source_column) || Map.get(object, to_str(source_column))
 22
 23     cond do
 24       length(path) == 0 -> new_value
 25       true -> __MODULE__.get_in(new_value, path)
 26     end
 27   end
 28 end
~
~

dimitarvp

dimitarvp

Seems like object is nil then.

al2o3cr

al2o3cr

This trace (along with the exception) tells you that build_full_name is calling get_in in a way that ultimately results in trying to do Map.get(nil, :name).

There are a lot of different ways to resolve this, depending on code that’s not visible:

  • get_in could have additional code added to guard against nil inputs. This could be as simple as an extra head def get_in(nil, _), do: nil
  • build_full_name could have additional code added to avoid calling get_in with values that cause a crash. Hard to say without any code from that function.
  • find_or_create_geos could have additional code added to avoid calling build_full_name with values that cause a crash. Again, hard to say without code.
  • either build_full_name or find_or_create_geos - or even some function farther up the stack - could have a bug that accidentally produces unexpected nils. For instance, a call to get_in(something, [:dr, :name]) where :dr is a typo for :de
— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews