microsoft/typescript-go · error · ErrClientError
%w: project has no program
Error message
%w: project has no program
What it means
Within a snapshot, the project handle resolved to a live project.Project, but proj.GetProgram() returned nil, so no compiler.Program exists for that project in this snapshot. Checker-backed requests (setupChecker -> sd.getProgram) therefore fail with "api: client error: project has no program". The project exists in the ProjectCollection but a program was never constructed for it - typically because its configuration failed to load or it contains no compilable files.
Source
Thrown at internal/api/session.go:86
// and allow clean teardown when a project is removed.
type projectRegistryData struct {
typeRegistry map[TypeID]*checker.Type
typeRegistryMu sync.RWMutex
signatureRegistry map[SignatureID]*checker.Signature
signatureRegistryMu sync.RWMutex
}
// getProgram looks up a program from a project handle within this snapshot.
func (sd *snapshotData) getProgram(projectHandle ProjectID) (*compiler.Program, error) {
proj, err := sd.getProject(projectHandle)
if err != nil {
return nil, err
}
program := proj.GetProgram()
if program == nil {
return nil, fmt.Errorf("%w: project has no program", ErrClientError)
}
return program, nil
}
// getProject looks up a project from a project handle within this snapshot.
func (sd *snapshotData) getProject(projectHandle ProjectID) (*project.Project, error) {
projectName := parseProjectHandle(projectHandle)
proj := sd.snapshot.ProjectCollection.GetProjectByPath(projectName)
if proj == nil {
return nil, fmt.Errorf("%w: project %s not found", ErrClientError, projectName)
}
return proj, nil
}
// nodeHandleFrom creates an index-based node handle (index.kind.path), building a node index table
// for the file on-demand if needed.
func (sd *snapshotData) nodeHandleFrom(node *ast.Node) NodeHandle {View on GitHub (pinned to 1bcfa18d79)
Solutions
- Re-run updateSnapshot with the project's files opened and confirm it succeeds before issuing checker queries
- Validate the project's config first with the parseConfigFile / parseCommandLine requests and fix any reported errors
- Use getDefaultProjectForFile for the file you are querying - it returns a project that actually has the file loaded
- Confirm the project has source files via getSourceFileNames before assuming a program exists
Example fix
// before
const res = await call("getTypeAtPosition", { snapshot, project, file, position }); // project has no program
// after
const proj = await call("getDefaultProjectForFile", { snapshot, file }); // project that loaded `file`
if (proj) {
const res = await call("getTypeAtPosition", { snapshot, project: proj, file, position });
} Defensive patterns
Strategy: validation
Validate before calling
// TS client: confirm the project actually loaded files before checker calls.
const names = await call("getSourceFileNames", { snapshot, project });
if (!names || names.length === 0) {
throw new Error(`project ${project} has no loaded files - program not built; check its tsconfig`);
}
// only now issue getTypeAtPosition / getSignaturesOfType / ... Try / catch
try {
return await call(method, params);
} catch (e) {
if (String(e).includes("project has no program")) {
// config likely broken: re-open the project's files via updateSnapshot,
// validate tsconfig via parseConfigFile, then retry once with the fresh handle
const fresh = await reopenProject(file);
return await call(method, { ...params, snapshot: fresh.snapshot, project: fresh.project });
}
throw e;
} Prevention
- Run updateSnapshot and wait for its response before the first checker query per project
- Prefer getDefaultProjectForFile over cached project handles for file-scoped queries
- Surface parseConfigFile diagnostics before treating a project as queryable
- Treat 'project has no program' as a config problem first: check tsconfig syntax, extends resolution, and include patterns
When it happens
Trigger: Calling type/checker methods (getTypeAtPosition, getSignaturesOfType, getResolvedSignature, ...) with a project handle whose tsconfig failed to parse or whose file list is empty; using a project handle for a config project discovered but not fully loaded in this snapshot; querying before the updateSnapshot that opens the project's files has completed.
Common situations: A broken tsconfig.json (syntax errors, unresolvable extends) so program construction silently yields nil; a project whose include/exclude patterns match zero files; a project reference that was never loaded; racing an editor integration's first checker query against snapshot initialization.
Related errors
- %w: project %s not found
- %w: symbol handle %d not found in snapshot registry
- %w: empty project ID for type handle %d
- %w: type handle %d not found (no registry for project %s)
- %w: type handle %d not found in project registry
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/e6fd9f4df099d444.
Report an issue: GitHub.