wavetermdev/waveterm · error
mach_timebase_info returned denom=0
Error message
mach_timebase_info returned denom=0
What it means
mach_timebase_info succeeded but returned denom=0, which would cause a division by zero when computing darwinTimeScale = numer/denom. The library treats this defensively as an init failure and caches it via sync.Once, disabling CPU-time scaling for the process.
Source
Thrown at pkg/util/procinfo/procinfo_darwin.go:124
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
ret := darwinProcPidInfo(
pid,
procPidTaskInfo,
0,View on GitHub (pinned to a4447c1563)
Solutions
- Verify machTimebaseInfo matches the C struct mach_timebase_info { uint32 numer; uint32 denom; } (two uint32, no padding)
- Update purego and re-test; binding regressions can mis-map arguments
- Log the full tb struct (numer and denom) to confirm the corruption pattern
- Avoid re-running in the same process — sync.Once caches the error; restart after fixing
- Fall back to a known-good scale (numer=1, denom=1) if exact CPU times are non-critical
Example fix
// before
darwinTimeScale = float64(tb.Numer) / float64(tb.Denom)
// after
if tb.Denom == 0 {
darwinProcInitErr = fmt.Errorf("mach_timebase_info returned denom=0 (numer=%d)", tb.Numer)
return
}
darwinTimeScale = float64(tb.Numer) / float64(tb.Denom) Defensive patterns
Strategy: try-catch
Try / catch
info, err := procinfo.GetProcInfo(ctx, nil, pid)
if err != nil && strings.Contains(err.Error(), "denom=0") {
// timebase invalid; treat CPU-time data as unavailable
} Prevention
- Verify machTimebaseInfo struct matches the C layout (two uint32)
- Test on all supported macOS versions and architectures (amd64/arm64)
- Handle the error at startup rather than per-call, since it is cached
- Prefer graceful degradation (skip CPU scaling) over hard failure
When it happens
Trigger: First GetProcInfo call on darwin when the kernel fills machTimebaseInfo with Numer>0, Denom==0 — practically only from memory corruption, a misdeclared struct layout, or garbage from a bad FFI binding.
Common situations: Struct ABI mismatch after an OS/SDK change so the Denom field reads wrong memory; custom toolchains or emulators (e.g. Rosetta edge cases) returning malformed output.
Related errors
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/34125facb0886934.
Report an issue: GitHub.