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 procTaskInfoView on GitHub (pinned to a4447c1563)
Solutions
- Check the logged return code: 4 = KERN_INVALID_ARGUMENT, 1 = KERN_INVALID_ADDRESS — usually a binding/ABI issue
- Update purego and verify the machTimebaseInfoFunc signature matches mach_timebase_info(info *)
- Reproduce in a minimal Go program calling darwinMachTimebase to isolate environment vs. binding
- Restart the process — a transient kernel failure is cached forever by sync.Once
- 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
- Keep the purego binding signature matching mach_timebase_info exactly
- Test procinfo initialization early in app startup to surface env problems
- Restart after failure — sync.Once means in-process retries never succeed
- Log the kernel return code for diagnosis
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.