go-delve/delve · error
NtQueryInformationThread failed: it returns 0x%x
Error message
NtQueryInformationThread failed: it returns 0x%x
What it means
Delve's native Windows backend calls NtQueryInformationThread with ThreadBasicInformation to obtain the thread's TEB base address when reading CPU registers. If the NT syscall returns a non-success NTSTATUS, the thread context cannot be assembled and an AMD64Registers object cannot be created. This typically means the thread handle is invalid, the thread has exited, or access rights are insufficient.
Source
Thrown at pkg/proc/native/threads_windows_amd64.go:29
)
func newContext() *winutil.AMD64CONTEXT {
return winutil.NewAMD64CONTEXT()
}
func registers(t *nativeThread) (proc.Registers, error) {
context := newContext()
context.SetFlags(_CONTEXT_ALL)
err := t.getContext(context)
if err != nil {
return nil, err
}
var threadInfo _THREAD_BASIC_INFORMATION
status := _NtQueryInformationThread(t.os.hThread, _ThreadBasicInformation, &threadInfo, uint32(unsafe.Sizeof(threadInfo)), nil)
if !_NT_SUCCESS(status) {
return nil, fmt.Errorf("NtQueryInformationThread failed: it returns 0x%x", status)
}
return winutil.NewAMD64Registers(context, uint64(threadInfo.TebBaseAddress)), nil
}
func (t *nativeThread) setContext(context *winutil.AMD64CONTEXT) error {
return _SetThreadContext(t.os.hThread, context)
}
func (t *nativeThread) getContext(context *winutil.AMD64CONTEXT) error {
return _GetThreadContext(t.os.hThread, context)
}
func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error {
return t.setContext(savedRegs.(*winutil.AMD64Registers).Context)
}
func (t *nativeThread) withDebugRegisters(f func(*amd64util.DebugRegisters) error) error {View on GitHub (pinned to a23773e6c3)
Solutions
- Retry the operation; transient races with thread exit usually resolve on a fresh stop state
- Re-list threads and only read registers for threads still in the target's thread list
- Run the debugger elevated (Administrator) to ensure sufficient handle access rights
- Check for security software interfering with debugger handle permissions
Example fix
// before
regs, err := thread.Registers()
// after
if !tg.HasThread(thread.ThreadID()) {
return nil // thread exited, skip
}
regs, err := thread.Registers()
if err != nil {
if isDeadThread(err) { return nil }
return err
} Defensive patterns
Strategy: retry
Validate before calling
if tg.HasThread(thread.ThreadID()) { /* safe to read registers */ } Type guard
func threadAlive(t proc.Thread, tg *proc.TargetGroup) bool { return tg.HasThread(t.ThreadID()) } Try / catch
regs, err := thread.Registers(); if err != nil { if strings.Contains(err.Error(), "NtQueryInformationThread") { /* thread likely exited; refresh thread list and retry once */ } else { return err } } Prevention
- Always refresh the thread list after each stop before reading registers
- Run the debugger with elevated privileges on Windows
- Skip register reads for threads absent from the target's thread list
- Keep antivirus exclusions for your dev debugger tooling
When it happens
Trigger: Calling Registers() on a native Windows thread whose OS thread has exited between stop and register read, or whose hThread handle was opened without THREAD_QUERY_INFORMATION rights.
Common situations: Debugging a rapidly exiting thread (race between thread death and register read); attaching to a process with restricted privileges; antivirus/security software blocking handle access; reading registers of a dead thread in a multithreaded program.
Related errors
- short read
- could not restore registers: %v
- wrong number of bytes for register %s (%d)
- changing register %d not implemented
- changing register %d not implemented
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/d8c58907efa700b3.
Report an issue: GitHub.