microsoft/typescript-go · error
project not found for update: %s
Error message
project not found for update: %s
What it means
Raised during the update phase of project collection building: the builder iterates apiState.openProjects (accumulated from earlier open requests) and must run updateProgram on each — but a config path is present in open-projects state while b.configuredProjects no longer has an entry for it. That means the project was closed/evicted from the registry while the API still counts it as open, an internal state divergence the builder refuses to paper over.
Source
Thrown at internal/project/projectcollectionbuilder.go:212
if apiRequest.OpenFiles != nil {
for uri := range apiRequest.OpenFiles.Keys() {
fileName := uri.FileName()
path := b.toPath(fileName)
if b.apiState.openFiles == nil {
b.apiState.openFiles = make(map[tspath.Path]apiOpenedFile)
}
entry := b.apiState.openFiles[path]
entry.fileName = fileName
entry.refCount++
b.apiState.openFiles[path] = entry
}
}
for configPath := range b.apiState.openProjects {
if entry, ok := b.configuredProjects.Load(configPath); ok {
b.updateProgram(entry, logger)
} else {
return fmt.Errorf("project not found for update: %s", configPath)
}
}
for _, overlay := range b.fs.overlays {
if entry := b.findDefaultConfiguredProject(overlay.FileName(), b.toPath(overlay.FileName())); entry != nil {
delete(projectsToClose, entry.Value().configFilePath)
}
}
for projectPath := range projectsToClose {
if entry, ok := b.configuredProjects.Load(projectPath); ok {
b.deleteConfiguredProject(entry, logger)
}
}
// Ensure each API-opened file is placed like LSP's textDocument/didOpen: search
// up ancestor directories for a configured project that contains it, and only
// fall back to the inferred project if none is found. This also keeps alreadyView on GitHub (pinned to 1bcfa18d79)
Solutions
- Re-open the project (it will be re-created via findOrCreateProject) before issuing the next update
- Serialize open/close/update requests per config path instead of racing them
- If the project was intentionally closed, also remove it from your open-projects tracking so updates skip it
Example fix
// before
api.Update(ctx, req) // openProjects still lists a closed project
// after
if !api.IsProjectOpen(configPath) {
api.Open(ctx, configPath) // re-materialize before update
}
api.Update(ctx, req) Defensive patterns
Strategy: validation
Validate before calling
// verify the project is still open before issuing updates
for cfg := range myOpenProjects {
if !apiSession.ProjectExists(cfg) {
if err := apiSession.Open(cfg); err != nil {
return err
}
}
}
apiSession.Update(ctx) Try / catch
err := builder.Build(apiRequest)
if err != nil && strings.Contains(err.Error(), "project not found for update") {
cfgPath := extractPath(err) // parse %s from the message
apiSession.Open(cfgPath) // re-materialize, then retry once
return builder.Build(apiRequest)
} Prevention
- Serialize open/close/update calls per config path; avoid racing watchers
- After closing a project, stop updating it and clear it from your open set
- Treat a config-file deletion as a signal to drop dependent update traffic
When it happens
Trigger: Project closed (config file deleted, or a close-projects request) between the open call and the next update; failed loads evicting the configured project while refcounts in apiState remain; interleaved open/close/update API requests hitting a race; config file invalidated by watch events mid-sequence.
Common situations: Rapid open→update sequences from automation while file watchers concurrently remove projects; tsconfig deleted between requests; concurrent API clients one closing and one updating the same project.
Related errors
- %w: project has no program
- Language server is not running.
- Cannot run a temporary file update on an inactive snapshot
- Snapshot is disposed
- Cannot run a temporary file update on an inactive snapshot
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/b015aef802e49fb1.
Report an issue: GitHub.