go-delve/delve · error
could not decode first frame
Error message
could not decode first frame
What it means
ThreadScope builds an EvalScope for evaluating expressions in the context of a paused OS thread. It requests a 1-frame stack trace; if the trace decodes to zero frames, delve cannot determine where the thread stopped and throws this error. It is thrown when ThreadStacktrace succeeds but returns no frames, so no PC/Fn context exists to evaluate against.
Source
Thrown at pkg/proc/eval.go:166
maxaddr = uint64(frames[0].Regs.CFA)
}
if maxaddr > minaddr && maxaddr-minaddr < maxFramePrefetchSize {
thread = cacheMemory(thread, minaddr, int(maxaddr-minaddr))
}
s := &EvalScope{Location: frames[0].Call, Regs: frames[0].Regs, Mem: thread, g: g, BinInfo: t.BinInfo(), target: t, frameOffset: frames[0].FrameOffset(), threadID: threadID}
s.PC = frames[0].lastpc
return s
}
// ThreadScope returns an EvalScope for the given thread.
func ThreadScope(t *Target, thread Thread) (*EvalScope, error) {
locations, err := ThreadStacktrace(t, thread, 1)
if err != nil {
return nil, err
}
if len(locations) < 1 {
return nil, errors.New("could not decode first frame")
}
return FrameToScope(t, thread.ProcessMemory(), nil, thread.ThreadID(), locations...), nil
}
// GoroutineScope returns an EvalScope for the goroutine running on the given thread.
func GoroutineScope(t *Target, thread Thread) (*EvalScope, error) {
locations, err := ThreadStacktrace(t, thread, 1)
if err != nil {
return nil, err
}
if len(locations) < 1 {
return nil, errors.New("could not decode first frame")
}
g, err := GetG(thread)
if err != nil {
return nil, err
}
threadID := 0View on GitHub (pinned to a23773e6c3)
Solutions
- Use GoroutineScope(t, thread) instead, which resolves the goroutine running on the thread and often succeeds where the raw thread frame decode yields nothing.
- Retry after the target stops again (continue and hit a breakpoint); transient states during attach often resolve once runtime metadata is loaded.
- Verify the binary has DWARF debug info (not stripped) so stack decoding can produce frames.
- Enumerate valid threads with process threads / ListThreads and pick a thread that has a resolvable goroutine.
Example fix
// before
scope, err := proc.ThreadScope(t, thread)
// after
scope, err := proc.GoroutineScope(t, thread)
if err != nil {
// thread has no decodable frames; skip or retry after next stop
return err
} Defensive patterns
Strategy: fallback
Validate before calling
locs, err := proc.ThreadStacktrace(t, thread, 1)
if err != nil || len(locs) < 1 {
// scope will fail; use goroutine-based scope or skip thread
return nil
} Type guard
func threadHasFrames(t *proc.Target, th proc.Thread) bool {
locs, err := proc.ThreadStacktrace(t, th, 1)
return err == nil && len(locs) >= 1
} Try / catch
scope, err := proc.ThreadScope(t, thread)
if err != nil && strings.Contains(err.Error(), "could not decode first frame") {
scope, err = proc.GoroutineScope(t, thread)
}
if err != nil { return err } Prevention
- Prefer GoroutineScope over ThreadScope for expression evaluation
- Skip threads without decodable frames when iterating all threads
- Ensure binaries keep DWARF debug info
- Retry evaluation on the next stop event after attach
When it happens
Trigger: Calling ThreadScope on a thread whose stack cannot be decoded: thread stopped in code without frame metadata, thread just created/killed between attach and stack walk, or a corrupted/unreadable stack for that thread ID.
Common situations: Attaching to a process where a thread is stopped in a syscall stub, signal trampoline, or early runtime startup before G frames exist; debugging stripped or partially-loaded binaries; racing with thread exit during attach.
Related errors
- Frame %d does not exist in goroutine %d
- Frame %d only has %d deferred calls
- unable to find function context
- unable to find locals: no debug information present in binar
- no address for escaped variable
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/8e4d3c61a6de2712.
Report an issue: GitHub.