cilium/cilium · error

clockSource is nil

Error message

clockSource is nil

What it means

NewCTTimeToSecConverter builds a timestamp-to-seconds converter based on the agent-reported clocksource. A nil clockSource argument gives no mode information, so the constructor returns this error immediately instead of dereferencing nil. It is a fail-fast guard for callers that skipped clocksource discovery.

Source

Thrown at pkg/maps/timestamp/timestamp.go:104

		return t / 1000000000, nil
	case models.ClockSourceModeJiffies:
		j, err := probes.Jiffies()
		if err != nil {
			return 0, err
		}
		return j >> bpfMonoScaler, nil
	default:
		return 0, fmt.Errorf("invalid clocksource: %s", clockSource.Mode)
	}
}

type TimestampConverter func(timestamp uint64) uint64

// Returns a function that converts a CT timestamp from clocksource units into
// seconds.
func NewCTTimeToSecConverter(clockSource *models.ClockSource) (TimestampConverter, error) {
	if clockSource == nil {
		return nil, fmt.Errorf("clockSource is nil")
	}
	switch clockSource.Mode {
	case models.ClockSourceModeKtime:
		converter := func(timestamp uint64) uint64 {
			return timestamp
		}
		return converter, nil
	case models.ClockSourceModeJiffies:
		hertz := clockSource.Hertz
		if hertz == 0 {
			return nil, fmt.Errorf("invalid clock Hertz value (0)")
		}
		converter := func(timestamp uint64) uint64 {
			return (timestamp << bpfMonoScaler) / uint64(hertz)
		}
		return converter, nil
	default:
		return nil, fmt.Errorf("invalid clocksource: %s", clockSource.Mode)

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Check and propagate the error from GetClockSourceFromAgent before constructing the converter
  2. Fall back to reading the clocksource from the agent config file when the API returns none
  3. Never pass a literal nil; validate the models.ClockSource at the call site

Example fix

// before: nil deref risk
clockSource, _ := GetClockSourceFromAgent(svc)
conv, err := NewCTTimeToSecConverter(clockSource)
// after: check error and nil
clockSource, err := GetClockSourceFromAgent(svc)
if err != nil {
    return nil, err
}
conv, err := NewCTTimeToSecConverter(clockSource)
Defensive patterns

Strategy: validation

Validate before calling

// Guard before constructing the converter
if clockSource == nil {
    return errors.New("clocksource must be resolved (API or config) before building converter")
}

Type guard

func hasClockSource(cs *models.ClockSource) bool {
    return cs != nil && cs.Mode != ""
}

Try / catch

// Go: nil-check pattern
clockSource, err := GetClockSourceFromAgent(svc)
if err != nil {
    return fmt.Errorf("cannot build time converter: %w", err)
}
conv, err := NewCTTimeToSecConverter(clockSource)
if err != nil {
    return err
}

Prevention

When it happens

Trigger: Passing nil to NewCTTimeToSecConverter — typically when GetClockSourceFromAgent already failed, an error path was ignored upstream, or a caller hardcodes nil assuming ktime.

Common situations: Ignoring the error from GetClockSourceFromAgent and using the nil result; wiring the converter before the agent health endpoint is available; tests passing nil stubs.

Related errors


AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31). Data as JSON: /api/errors/d4102c095f235be4. Report an issue: GitHub.