cayleygraph/cayley · error

unsupported time format: %T: %v

Error message

unsupported time format: %T: %v

What it means

The SQL quadstore scans time column values into a NullTime wrapper supporting a limited set of driver value shapes (e.g. []byte/string in "2006-01-02 15:04:05.999999", time.Time, etc.). If the driver returns a value whose Go type isn't handled by the switch, Scan reports this error including the Go type (%T) and value.

Source

Thrown at graph/sql/quadstore.go:604

}

// Scan implements the Scanner interface.
func (nt *NullTime) Scan(value interface{}) error {
	if value == nil {
		nt.Time, nt.Valid = time.Time{}, false
		return nil
	}
	switch value := value.(type) {
	case time.Time:
		nt.Time, nt.Valid = value, true
	case []byte:
		t, err := time.Parse("2006-01-02 15:04:05.999999", string(value))
		if err != nil {
			return err
		}
		nt.Time, nt.Valid = t, true
	default:
		return fmt.Errorf("unsupported time format: %T: %v", value, value)
	}
	return nil
}

// Value implements the driver Valuer interface.
func (nt NullTime) Value() (driver.Value, error) {
	if !nt.Valid {
		return nil, nil
	}
	return nt.Time, nil
}

func (qs *QuadStore) NameOf(v graph.Ref) (quad.Value, error) {
	if v == nil {
		return nil, nil
	} else if v, ok := v.(refs.PreFetchedValue); ok {
		return v.NameOf(), nil
	}

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Check the actual timestamp format stored in the database column and align it with "2006-01-02 15:04:05.999999"
  2. Set the connection DSN to return time as time.Time (e.g. parseTime=true for MySQL) so Scan receives driver.Time instead of a string
  3. Normalize the column values (UPDATE table SET col = STR_TO_DATE(...)) to the expected format
  4. Extend NullTypedTime.Scan to handle the driver's representation in your fork

Example fix

// before
db, _ := sql.Open("mysql", "user:pw@/db") // returns strings for DATETIME
// after
db, _ := sql.Open("mysql", "user:pw@/db?parseTime=true") // returns time.Time
Defensive patterns

Strategy: try-catch

Validate before calling

if !strings.Contains(err.Error(), "unsupported time format") {
    return err
}
// else fix DSN/format and retry once

Type guard

if bt, ok := value.([]byte); ok {
    _, err := time.Parse("2006-01-02 15:04:05.999999", string(bt))
    return err
}
return fmt.Errorf("unexpected time value type %T", value)

Try / catch

val, err := qs.NameOf(h)
if err != nil && strings.Contains(err.Error(), "unsupported time format") {
    // reconfigure driver to return time.Time (e.g. parseTime=true) and retry
}

Prevention

When it happens

Trigger: A database driver returning timestamps in an unexpected representation, e.g. a string with timezone info like "2020-01-02T03:04:05Z" that fails Parse, or []uint8 with a nonstandard date format for that DB.

Common situations: MySQL driver returning DATE/DATETIME in a format with fractional-second or timezone differences; switching drivers so NullTypedTime.Scan receives raw strings it can't parse; storing timestamps written by other tools in a different format.

Related errors


AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06). Data as JSON: /api/errors/4f0ef2162e6ca237. Report an issue: GitHub.