wavetermdev/waveterm · error

mach_timebase_info failed: %d

Error message

mach_timebase_info failed: %d

What it means

mach_timebase_info was called through libSystem and returned a non-zero Mach kernel return code (kern_return_t != KERN_SUCCESS). This call converts mach absolute time units to nanoseconds and is required to scale CPU times. The failure is cached for the process lifetime via sync.Once.

Source

Thrown at pkg/util/procinfo/procinfo_darwin.go:120

	return info, nil
}

func initDarwinProcFuncs() error {
	darwinProcOnce.Do(func() {
		handle, err := purego.Dlopen(systemLibPath, purego.RTLD_LAZY|purego.RTLD_GLOBAL)
		if err != nil {
			darwinProcInitErr = fmt.Errorf("dlopen %s: %w", systemLibPath, err)
			return
		}
		darwinLibHandle = handle

		purego.RegisterLibFunc(&darwinProcPidInfo, darwinLibHandle, procPidInfoSym)
		purego.RegisterLibFunc(&darwinMachTimebase, darwinLibHandle, machTimebaseSym)

		var tb machTimebaseInfo
		if rc := darwinMachTimebase(uintptr(unsafe.Pointer(&tb))); rc != kernSuccess {
			darwinProcInitErr = fmt.Errorf("mach_timebase_info failed: %d", rc)
			return
		}
		if tb.Denom == 0 {
			darwinProcInitErr = fmt.Errorf("mach_timebase_info returned denom=0")
			return
		}

		darwinTimeScale = float64(tb.Numer) / float64(tb.Denom)
	})
	return darwinProcInitErr
}

func getDarwinProcTaskInfo(pid int32) (*procTaskInfo, error) {
	if err := initDarwinProcFuncs(); err != nil {
		return nil, err
	}

	var ti procTaskInfo

View on GitHub (pinned to a4447c1563)

Solutions

  1. Check the logged return code: 4 = KERN_INVALID_ARGUMENT, 1 = KERN_INVALID_ADDRESS — usually a binding/ABI issue
  2. Update purego and verify the machTimebaseInfoFunc signature matches mach_timebase_info(info *)
  3. Reproduce in a minimal Go program calling darwinMachTimebase to isolate environment vs. binding
  4. Restart the process — a transient kernel failure is cached forever by sync.Once
  5. Test on a stock macOS host; report an issue if it fails there

Example fix

// before
if rc := darwinMachTimebase(uintptr(unsafe.Pointer(&tb))); rc != kernSuccess {
    darwinProcInitErr = fmt.Errorf("mach_timebase_info failed: %d", rc)
// after (fallback to 1:1 scale instead of failing permanently)
if rc := darwinMachTimebase(uintptr(unsafe.Pointer(&tb))); rc != kernSuccess {
    tb = machTimebaseInfo{Numer: 1, Denom: 1} // degraded: skip CPU-time scaling
}
Defensive patterns

Strategy: try-catch

Try / catch

info, err := procinfo.GetProcInfo(ctx, nil, pid)
if err != nil && strings.Contains(err.Error(), "mach_timebase_info failed") {
    // mach init failed; CPU times will be unavailable — use fallback metrics
}

Prevention

When it happens

Trigger: First GetProcInfo call on darwin; the darwinMachTimebase function pointer (bound to mach_timebase_info) returns rc != 0, e.g. KERN_INVALID_ADDRESS if the bound symbol/ABI is wrong or the Mach port/task context is unavailable.

Common situations: Running in an environment without a Mach task context (rare, e.g. unusual emulation or a bad purego binding signature after an OS update); mismatched function signature causing garbage arguments.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/255da6ebc0cf2197. Report an issue: GitHub.