#132878·grafana

Stars: single NULL star.updated row breaks all star reads/writes for that user (500 "expected stars object")

Author: kavinsk1Created Sep 17, 2026Updated Sep 17, 2026
Labelstype/bugarea/backend/apiarea/backend/db/sqlitearea/backend/db/sqlautomated-triage

What happened?

For one specific user, every dashboard star operation fails: clicking the star icon returns HTTP 500, and the "Starred" section of the nav renders empty even though the user has valid star rows in the database. Other users on the same instance are unaffected.

Log output for the failing user:

logger=grafana-apiserver level=error msg="Unhandled Error" err="apiserver received an error that is not an metav1.Status: &errors.errorString{s:\"expected stars object\"}: expected stars object"
logger=context userId=2 level=error msg="Request Completed" method=POST path=/api/user/stars/dashboard/uid/business-kpis status=500 error="expected stars object"

Root cause

The star table schema declares updated as nullable (updated DATETIME NULL), but the collections API's legacy bridge scans it into a bare time.Time:

pkg/registry/apis/collections/legacy/sql.go, in getDashboardStars:

var updated time.Time
...
err := rows.Scan(&orgID, &userUID, &dashboardUID, &updated)

A single row with updated = NULL makes this Scan fail. Because sql_dashboard_stars.sql orders by s.updated asc and SQLite sorts NULLs first, the poisoned row is scanned first, so getDashboardStars fails for every call touching that user:

  • DashboardStarsStorage.Get returns the scan error, which is not a NotFound
  • In stars_update.go (starsREST.Connect), a non-NotFound error from Get leaves current as nil, so the current.(*collections.Stars) type assertion fails and the handler responds with the misleading expected stars object error for both PUT and DELETE
  • The read path fails the same way, so the user's starred list renders empty

Net effect: one NULL in a legally-nullable column bricks the entire stars feature for that user, including the DELETE path that could have removed the offending row via the API.

NULL values in this column occur in practice: rows written by older Grafana versions or by operators backfilling dashboard_uid during migrations (the column was added later; the schema accepts NULL, so nothing flags the insert).

Steps to reproduce

  1. Star any dashboard as a user
  2. UPDATE star SET updated = NULL WHERE user_id = <that user>;
  3. Reload Grafana: the starred list is empty
  4. Click the star icon on any dashboard: POST /api/user/stars/dashboard/uid/... returns 500 "expected stars object"

Suggested fix

Scan into sql.NullTime in getDashboardStars and fall back to a zero time (the value only affects star display order). Separately, stars_update.go swallows the underlying error when Get fails with a non-NotFound error; returning that error instead of the type-assertion message would have made this diagnosable from the log alone.

Environment

  • Grafana 13.2.0 (f681b1359f6a0b8ecb9f2c49a88ac72b75bde73b), OSS, SQLite backend, deployed via kube-prometheus-stack