wavetermdev/waveterm · error
TermRef not current
Error message
TermRef not current
What it means
TermRef implements io.Writer by forwarding data to a terminal block via TermWrite. It refuses to write unless the underlying VDomRef has a currently-mounted/active terminal instance (tracked by the HasCurrent atomic flag). Writing to a stale, detached, or not-yet-mounted terminal ref yields this error instead of silently dropping bytes.
Source
Thrown at tsunami/app/hooks.go:42
func UseVDomRef() *vdom.VDomRef {
rc := engine.GetGlobalRenderContext()
val := engine.UseVDomRef(rc)
refVal, ok := val.(*vdom.VDomRef)
if !ok {
panic("UseVDomRef hook value is not a ref (possible out of order or conditional hooks)")
}
return refVal
}
// TermRef wraps a VDomRef and implements io.Writer by forwarding writes to the terminal.
type TermRef struct {
*vdom.VDomRef
}
// Write implements io.Writer by sending data to the terminal via TermWrite.
func (tr *TermRef) Write(p []byte) (n int, err error) {
if tr.VDomRef == nil || !tr.VDomRef.HasCurrent.Load() {
return 0, fmt.Errorf("TermRef not current")
}
err = TermWrite(tr.VDomRef, string(p))
if err != nil {
return 0, err
}
return len(p), nil
}
// TermSize returns the current terminal size, or nil if not yet set.
func (tr *TermRef) TermSize() *vdom.VDomTermSize {
if tr.VDomRef == nil {
return nil
}
return tr.VDomRef.TermSize
}
// UseTermRef returns a TermRef that can be passed as a ref to "wave:term" elements
// and also implements io.Writer for writing directly to the terminal.View on GitHub (pinned to a4447c1563)
Solutions
- Check tr.VDomRef != nil and tr.VDomRef.HasCurrent.Load() before writing, and re-acquire a fresh ref if stale
- Retry after the component mounts (wait for HasCurrent to become true)
- Route writes through a channel/queue drained only while the ref is current
- Treat the error as 'terminal gone' and stop writing rather than retrying forever
Example fix
// before
n, err := termRef.Write(data)
// after
if termRef.VDomRef == nil || !termRef.VDomRef.HasCurrent.Load() {
return // terminal not attached; skip or buffer
}
n, err := termRef.Write(data) Defensive patterns
Strategy: validation
Validate before calling
func canWrite(tr *tsunami.TermRef) bool {
return tr != nil && tr.VDomRef != nil && tr.VDomRef.HasCurrent.Load()
}
if canWrite(tr) {
tr.Write(data)
} Type guard
func isCurrentTermRef(tr *tsunami.TermRef) bool {
return tr != nil && tr.VDomRef != nil && tr.VDomRef.HasCurrent.Load()
} Try / catch
n, err := tr.Write(p)
if err != nil && err.Error() == "TermRef not current" {
// buffer or drop; terminal detached
} Prevention
- Always check HasCurrent before writing to a TermRef
- Never hold a TermRef across block close/reopen; reacquire it
- Marshal writes through a single goroutine that validates currency
When it happens
Trigger: Calling TermRef.Write (directly or via fmt.Fprintf/io.WriteString) when tr.VDomRef is nil, or when the vdom ref exists but HasCurrent is false — e.g. before the block's component mounts the ref, after the block is closed/destroyed, or after a re-render replaced the ref.
Common situations: Writing terminal output from a background goroutine after the UI block was closed; writing during startup before the component attached; holding a TermRef across a block close/reopen cycle.
Related errors
- bind tags must be self closing
- doctype not supported
- Cannot get last command data without shell integration
- beginning of file
- procinfo: process not found
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/a828d45c1084be1a.
Report an issue: GitHub.