Files
music_library/backlog/tasks/ml-171 - Fix-Oban-Web-crons-page-crash-MatchError-in-sparkline-from-SQLite-datetime-string.md
T
2026-05-09 06:29:38 +01:00

2.6 KiB

id, title, status, assignee, created_date, labels, dependencies, references, modified_files, priority
id title status assignee created_date labels dependencies references modified_files priority
ML-171 Fix Oban Web crons page crash: MatchError in sparkline from SQLite datetime string To Do
2026-05-09 05:28
bug
oban-web
sqlite
https://github.com/oban-bg/oban_web/blob/main/lib/oban/web/live/crons/table_component.ex#L78-L85
https://github.com/oban-bg/oban_web/blob/main/lib/oban/web/queries/cron_query.ex#L164-L177
lib/music_library_web/live/oban/crons/table_component.ex
medium

Description

Summary

The /dev/oban/crons dashboard page crashes with Elixir.MatchError when rendering cron job history sparklines. This happens because Oban Web's TableComponent.sparkline/1 calls DateTime.from_naive!/2 which expects a NaiveDateTime struct, but receives a raw ISO 8601 string from SQLite.

Root Cause

In Oban.Web.CronQuery.cron_history/2 (deps/oban_web/lib/oban/web/queries/cron_query.ex:164-177), the query selects:

finished_at: fragment("COALESCE(?, ?, ?)", j.completed_at, j.cancelled_at, j.discarded_at)

SQLite stores utc_datetime_usec fields as ISO 8601 text. While regular field references like j.scheduled_at are properly decoded to DateTime structs by Ecto, the fragment() call bypasses type decoding and returns a raw string like "2026-05-08T11:00:00.708342Z".

The sparkline function at Oban.Web.Crons.TableComponent line 81 then fails:

(job.finished_at || job.attempted_at || job.scheduled_at)
|> DateTime.from_naive!("Etc/UTC")  # 💥 expects NaiveDateTime, gets string

Error Details

  • ErrorTracker ID: 4039
  • Occurrences: 2 (both on 2026-05-08)
  • View: Oban.Web.DashboardLive (crons page)
  • Fingerprint: 2C5253F1AB9B5D61231B7579E912FD2F7C155738DBB4325275F14E844C5D7B0C

Approach

The sparkline/1 function is marked as @doc overridable: 1 in Oban Web, so we can override it in the app. The fix should handle both DateTime structs (PostgreSQL) and ISO 8601 strings (SQLite) by parsing strings through DateTime.from_iso8601!/1 first.

Alternatively, the fix could be applied upstream in Oban Web's CronQuery to use a typed fragment or cast the COALESCE result.

Acceptance Criteria

  • #1 Visiting /dev/oban/crons no longer crashes with MatchError
  • #2 Cron history sparklines render correctly showing job state colors
  • #3 The fix handles both DateTime structs (PostgreSQL) and ISO 8601 strings (SQLite)
  • #4 The overridden sparkline/1 function preserves the same visual output as upstream