go-delve/delve · error
cycle in load graph
Error message
cycle in load graph
What it means
The Starlark module loader in Delve's scripting REPL caches modules and tracks in-progress loads. If a module is requested while its own load is still in progress (the cache contains a nil placeholder for it), the loader returns 'cycle in load graph' to break infinite recursion — Starlark load statements must form a DAG.
Source
Thrown at pkg/terminal/starbind/repl.go:187
}
// MakeLoad returns a simple sequential implementation of module loading
// suitable for use in the REPL.
// Each function returned by MakeLoad accesses a distinct private cache.
func MakeLoad() func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
type entry struct {
globals starlark.StringDict
err error
}
var cache = make(map[string]*entry)
return func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
e, ok := cache[module]
if e == nil {
if ok {
// request for package whose loading is in progress
return nil, errors.New("cycle in load graph")
}
// Add a placeholder to indicate "load in progress".
cache[module] = nil
// Load it.
thread := &starlark.Thread{Name: "exec " + module, Load: thread.Load}
globals, err := execFileOptions(nil, thread, module, nil, nil)
e = &entry{globals, err}
// Update the cache.
cache[module] = e
}
return e.globals, e.err
}
}
View on GitHub (pinned to a23773e6c3)
Solutions
- Break the cycle: move the shared code into a third module both scripts load instead of loading each other.
- Remove self-loads: a module should never `load()` itself.
- Restructure so imports form a tree: leaf utility modules load nothing; higher-level scripts load the leaves.
Example fix
// before: a.star
load("b.star", "helper")
// b.star
load("a.star", "setup") # cycle!
// after: shared.star
helper = ... # move shared code here
// a.star
load("shared.star", "helper")
// b.star
load("shared.star", "helper") Defensive patterns
Strategy: validation
Validate before calling
def check_no_cycle(load_graph, entry):
seen, stack = set(), []
def visit(m):
if m in stack: raise Exception("cycle at " + m)
if m in seen: return
seen.add(m); stack.append(m)
for d in load_graph.get(m, []): visit(d)
stack.pop()
visit(entry) Prevention
- Never write load("self.star") inside a module
- Keep the module graph a DAG: shared code in leaf modules with no loads
- Audit mutual imports after refactoring scripts into modules
When it happens
Trigger: Two Starlark scripts loading each other (a.star loads b.star, b.star loads a.star), or a script loading itself (`load("a.star", ...)` inside a.star).
Common situations: Refactoring scripts into shared modules and accidentally creating mutual imports; copy-pasting load statements so a module re-imports its importer.
Related errors
- value not loaded
- not hashable
- argument of dlv_command is not a string
- wrong number of arguments
- argument of read_file was not a string
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/17876a7f8fada7f9.
Report an issue: GitHub.