JanDeDobbeleer/oh-my-posh · error

RoInitialize: 0x%08x

Error message

RoInitialize: 0x%08x

What it means

Before touching any WinRT API, the SMTC media player code calls RoInitialize with RO_INIT_MULTITHREADED on the locked OS thread. S_FALSE (1) means the thread was already initialized and is accepted; any other non-zero HRESULT is returned as this error, meaning WinRT could not be initialized on this thread and no media info can be queried.

Solutions

  1. If the HRESULT is 0x80010106 (E_CHANGEDMODE), run the prompt in a thread/process that has not pre-initialized COM as STA, or accept the media segment being unavailable
  2. Retry after freeing memory if the code is E_OUTOFMEMORY
  3. Check the host application's COM apartment model if embedding oh-my-posh
  4. Update Windows if the failure persists on a clean thread
Defensive patterns

Strategy: fallback

Try / catch

info, err := runtime.QueryMediaPlayer(env)
if err != nil {
	var hrErr interface{ HRESULT() uint32 }
	if errors.As(err, &hrErr) { /* inspect RoInitialize HRESULT */ }
	return mediaSegment{} // hide segment, prompt keeps rendering
}

Prevention

When it happens

Trigger: QueryMediaPlayer calling procRoInitialize and getting an HRESULT other than 0 (S_OK) or 1 (S_FALSE) - e.g. E_OUTOFMEMORY (0x8007000E) or E_CHANGEDMODE (0x80010106) when the thread is already initialized in a different apartment mode.

Common situations: Embedding oh-my-posh in a host process that already initialized COM on the thread as STA (single-threaded apartment); extremely low-memory conditions (E_OUTOFMEMORY); unusual threading environments in custom prompt hosts.

Related errors


AI-assisted analysis of JanDeDobbeleer/oh-my-posh@0976794618 (2026-08-31). Data as JSON: /api/errors/ad3b96409ed61ea0. Report an issue: GitHub.

Appendix: source

Thrown at src/runtime/smtc_windows.go:229

		}
		if time.Now().After(deadline) {
			return errors.New("async timed out")
		}
		time.Sleep(smtcAsyncPollInterval)
	}
}

func queryMediaPlayer(player string) (*MediaInfo, error) {
	// RoInitialize / RoUninitialize update thread-local state, so we have to
	// pin the goroutine to one OS thread for the duration of this call.
	goruntime.LockOSThread()
	defer goruntime.UnlockOSThread()

	// RO_INIT_MULTITHREADED = 1. S_FALSE (1) means already initialised on
	// this thread, which is fine — we still pair with RoUninitialize.
	hr, _, _ := procRoInitialize.Call(1)
	if hr != 0 && hr != 1 {
		return nil, fmt.Errorf("RoInitialize: 0x%08x", hr)
	}
	defer func() { _, _, _ = procRoUninitialize.Call() }()

	classID, err := newHString("Windows.Media.Control.GlobalSystemMediaTransportControlsSessionManager")
	if err != nil {
		return nil, err
	}
	defer classID.Close()

	var factory unsafe.Pointer
	hr, _, _ = procRoGetActivationFactory.Call(
		uintptr(classID),
		uintptr(unsafe.Pointer(&iidSMTCSessionManagerStatics)),
		uintptr(unsafe.Pointer(&factory)),
	)
	if hr != 0 {
		return nil, fmt.Errorf("RoGetActivationFactory: 0x%08x", hr)
	}

View on GitHub (pinned to 0976794618)