When SQL was trying to update detections during the tracking step, it crashed because the sequence_previous_cost provided in the SQL query was provided as "np.float64(0.3574944335646804)" instead of just 0.3574944335646804. This is apparently due to a recent change to the string representation of floats in Numpy 2.0+.
My error outputs are reproduced below.
2026-07-17 18:42:24 [info ] Clearing existing sequences for 2024-06-06
2026-07-17 18:42:24 [info ] Calculating tracks for 2024-06-06
2026-07-17 18:42:24 [info ] Saving tracks to database
╭───────────────────────────────────────────────────────────────────────────────────────── Traceback (most recent call last) ──────────────────────────────────────────────────────────────────────────────────────────╮
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967 in _exec_single_context │
│ │
│ 1964 │ │ │ │ │ │ │ evt_handled = True │
│ 1965 │ │ │ │ │ │ │ break │
│ 1966 │ │ │ │ if not evt_handled: │
│ ❱ 1967 │ │ │ │ │ self.dialect.do_execute( │
│ 1968 │ │ │ │ │ │ cursor, str_statement, effective_parameters, context │
│ 1969 │ │ │ │ │ ) │
│ 1970 │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/engine/default.py:952 in do_execute │
│ │
│ 949 │ │ cursor.executemany(statement, parameters) │
│ 950 │ │
│ 951 │ def do_execute(self, cursor, statement, parameters, context=None): │
│ ❱ 952 │ │ cursor.execute(statement, parameters) │
│ 953 │ │
│ 954 │ def do_execute_no_params(self, cursor, statement, context=None): │
│ 955 │ │ cursor.execute(statement) │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
InvalidSchemaName: schema "np" does not exist
LINE 1: ... sequence_previous_id=232, sequence_previous_cost=np.float64...
^
The above exception was the direct cause of the following exception:
╭───────────────────────────────────────────────────────────────────────────────────────── Traceback (most recent call last) ──────────────────────────────────────────────────────────────────────────────────────────╮
│ /home/ter38/projects/ecco30/ami-data-companion/trapdata/cli/base.py:62 in run_pipeline │
│ │
│ 59 │ """ │
│ 60 │ Session = get_session_class(settings.database_url) │
│ 61 │ session = Session() │
│ ❱ 62 │ start_pipeline( │
│ 63 │ │ session=session, │
│ 64 │ │ image_base_path=settings.image_base_path, │
│ 65 │ │ settings=settings, │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/trapdata/ml/pipeline.py:87 in start_pipeline │
│ │
│ 84 │ │ ) │
│ 85 │ │ for event in events: │
│ 86 │ │ │ logger.info(f"Calculating tracks in event {event}") │
│ ❱ 87 │ │ │ ml.models.tracking.find_all_tracks( │
│ 88 │ │ │ │ monitoring_session=event, session=session │
│ 89 │ │ │ ) │
│ 90 │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/trapdata/ml/models/tracking.py:799 in find_all_tracks │
│ │
│ 796 │ │ │ commit=False, │
│ 797 │ │ ) │
│ 798 │ logger.info("Saving tracks to database") │
│ ❱ 799 │ session.flush() │
│ 800 │ session.commit() │
│ 801 │
│ 802 │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/orm/session.py:4331 in flush │
│ │
│ 4328 │ │ │ return │
│ 4329 │ │ try: │
│ 4330 │ │ │ self._flushing = True │
│ ❱ 4331 │ │ │ self._flush(objects) │
│ 4332 │ │ finally: │
│ 4333 │ │ │ self._flushing = False │
│ 4334 │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/orm/session.py:4466 in _flush │
│ │
│ 4463 │ │ │ transaction.commit() │
│ 4464 │ │ │
│ 4465 │ │ except: │
│ ❱ 4466 │ │ │ with util.safe_reraise(): │
│ 4467 │ │ │ │ transaction.rollback(_capture_exception=True) │
│ 4468 │ │
│ 4469 │ def bulk_save_objects( │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/util/langhelpers.py:224 in __exit__ │
│ │
│ 221 │ │ │ exc_type, exc_value, exc_tb = self._exc_info │
│ 222 │ │ │ assert exc_value is not None │
│ 223 │ │ │ self._exc_info = None # remove potential circular references │
│ ❱ 224 │ │ │ raise exc_value.with_traceback(exc_tb) │
│ 225 │ │ else: │
│ 226 │ │ │ self._exc_info = None # remove potential circular references │
│ 227 │ │ │ assert value is not None │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/orm/session.py:4427 in _flush │
│ │
│ 4424 │ │ try: │
│ 4425 │ │ │ self._warn_on_events = True │
│ 4426 │ │ │ try: │
│ ❱ 4427 │ │ │ │ flush_context.execute() │
│ 4428 │ │ │ finally: │
│ 4429 │ │ │ │ self._warn_on_events = False │
│ 4430 │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py:466 in execute │
│ │
│ 463 │ │ │ │ │ n.execute_aggregate(self, set_) │
│ 464 │ │ else: │
│ 465 │ │ │ for rec in topological.sort(self.dependencies, postsort_actions): │
│ ❱ 466 │ │ │ │ rec.execute(self) │
│ 467 │ │
│ 468 │ def finalize_flush_changes(self) -> None: │
│ 469 │ │ """Mark processed objects as clean / deleted after a successful │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py:642 in execute │
│ │
│ 639 │ │
│ 640 │ @util.preload_module("sqlalchemy.orm.persistence") │
│ 641 │ def execute(self, uow): │
│ ❱ 642 │ │ util.preloaded.orm_persistence.save_obj( │
│ 643 │ │ │ self.mapper, │
│ 644 │ │ │ uow.states_for_mapper_hierarchy(self.mapper, False, False), │
│ 645 │ │ │ uow, │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py:85 in save_obj │
│ │
│ 82 │ │ │ uowtransaction, table, states_to_update │
│ 83 │ │ ) │
│ 84 │ │ │
│ ❱ 85 │ │ _emit_update_statements( │
│ 86 │ │ │ base_mapper, │
│ 87 │ │ │ uowtransaction, │
│ 88 │ │ │ mapper, │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py:912 in _emit_update_statements │
│ │
│ 909 │ │ │ │ │ or (assert_singlerow and len(multiparams) == 1) │
│ 910 │ │ │ │ ) │
│ 911 │ │ │ │ │
│ ❱ 912 │ │ │ │ c = connection.execute( │
│ 913 │ │ │ │ │ statement, multiparams, execution_options=execution_options │
│ 914 │ │ │ │ ) │
│ 915 │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1419 in execute │
│ │
│ 1416 │ │ except AttributeError as err: │
│ 1417 │ │ │ raise exc.ObjectNotExecutableError(statement) from err │
│ 1418 │ │ else: │
│ ❱ 1419 │ │ │ return meth( │
│ 1420 │ │ │ │ self, │
│ 1421 │ │ │ │ distilled_parameters, │
│ 1422 │ │ │ │ execution_options or NO_OPTIONS, │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/sql/elements.py:527 in _execute_on_connection │
│ │
│ 524 │ │ if self.supports_execution: │
│ 525 │ │ │ if TYPE_CHECKING: │
│ 526 │ │ │ │ assert isinstance(self, Executable) │
│ ❱ 527 │ │ │ return connection._execute_clauseelement( │
│ 528 │ │ │ │ self, distilled_params, execution_options │
│ 529 │ │ │ ) │
│ 530 │ │ else: │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1641 in _execute_clauseelement │
│ │
│ 1638 │ │ │ schema_translate_map=schema_translate_map, │
│ 1639 │ │ │ linting=self.dialect.compiler_linting | compiler.WARN_LINTING, │
│ 1640 │ │ ) │
│ ❱ 1641 │ │ ret = self._execute_context( │
│ 1642 │ │ │ dialect, │
│ 1643 │ │ │ dialect.execution_ctx_cls._init_compiled, │
│ 1644 │ │ │ compiled_sql, │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1846 in _execute_context │
│ │
│ 1843 │ │ if context.execute_style is ExecuteStyle.INSERTMANYVALUES: │
│ 1844 │ │ │ return self._exec_insertmany_context(dialect, context) │
│ 1845 │ │ else: │
│ ❱ 1846 │ │ │ return self._exec_single_context( │
│ 1847 │ │ │ │ dialect, context, statement, parameters │
│ 1848 │ │ │ ) │
│ 1849 │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1986 in _exec_single_context │
│ │
│ 1983 │ │ │ result = context._setup_result_proxy() │
│ 1984 │ │ │
│ 1985 │ │ except BaseException as e: │
│ ❱ 1986 │ │ │ self._handle_dbapi_exception( │
│ 1987 │ │ │ │ e, str_statement, effective_parameters, cursor, context │
│ 1988 │ │ │ ) │
│ 1989 │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py:2363 in _handle_dbapi_exception │
│ │
│ 2360 │ │ │ │ raise newraise.with_traceback(exc_info[2]) from e │
│ 2361 │ │ │ elif should_wrap: │
│ 2362 │ │ │ │ assert sqlalchemy_exception is not None │
│ ❱ 2363 │ │ │ │ raise sqlalchemy_exception.with_traceback(exc_info[2]) from e │
│ 2364 │ │ │ else: │
│ 2365 │ │ │ │ assert exc_info[1] is not None │
│ 2366 │ │ │ │ raise exc_info[1].with_traceback(exc_info[2]) │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py:1967 in _exec_single_context │
│ │
│ 1964 │ │ │ │ │ │ │ evt_handled = True │
│ 1965 │ │ │ │ │ │ │ break │
│ 1966 │ │ │ │ if not evt_handled: │
│ ❱ 1967 │ │ │ │ │ self.dialect.do_execute( │
│ 1968 │ │ │ │ │ │ cursor, str_statement, effective_parameters, context │
│ 1969 │ │ │ │ │ ) │
│ 1970 │
│ │
│ /home/ter38/projects/ecco30/ami-data-companion/.venv/lib/python3.12/site-packages/sqlalchemy/engine/default.py:952 in do_execute │
│ │
│ 949 │ │ cursor.executemany(statement, parameters) │
│ 950 │ │
│ 951 │ def do_execute(self, cursor, statement, parameters, context=None): │
│ ❱ 952 │ │ cursor.execute(statement, parameters) │
│ 953 │ │
│ 954 │ def do_execute_no_params(self, cursor, statement, context=None): │
│ 955 │ │ cursor.execute(statement) │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
ProgrammingError: (psycopg2.errors.InvalidSchemaName) schema "np" does not exist
LINE 1: ... sequence_previous_id=232, sequence_previous_cost=np.float64...
^
[SQL: UPDATE detections SET sequence_id=%(sequence_id)s, sequence_frame=%(sequence_frame)s, sequence_previous_id=%(sequence_previous_id)s, sequence_previous_cost=%(sequence_previous_cost)s WHERE detections.id =
%(detections_id)s]
[parameters: {'sequence_id': '20240606-SEQ-232', 'sequence_frame': 1, 'sequence_previous_id': 232, 'sequence_previous_cost': np.float64(0.3574944335646804), 'detections_id': 278}]
(Background on this error at: https://sqlalche.me/e/20/f405)
When SQL was trying to update detections during the tracking step, it crashed because the
sequence_previous_costprovided in the SQL query was provided as"np.float64(0.3574944335646804)"instead of just0.3574944335646804. This is apparently due to a recent change to the string representation of floats in Numpy 2.0+.I patched this on my own system by wrapping float() around the
final_costvariable in the offending line:ami-data-companion/trapdata/ml/models/tracking.py
Line 601 in a33746a
My error outputs are reproduced below.