{"record":{"id":"e6fd9f4df099d444","repo":"microsoft/typescript-go","slug":"w-project-has-no-program","errorCode":null,"errorMessage":"%w: project has no program","messagePattern":"%w: project has no program","errorType":"validation","errorClass":"ErrClientError","httpStatus":null,"severity":"error","filePath":"internal/api/session.go","lineNumber":86,"sourceCode":"// and allow clean teardown when a project is removed.\ntype projectRegistryData struct {\n\ttypeRegistry   map[TypeID]*checker.Type\n\ttypeRegistryMu sync.RWMutex\n\n\tsignatureRegistry   map[SignatureID]*checker.Signature\n\tsignatureRegistryMu sync.RWMutex\n}\n\n// getProgram looks up a program from a project handle within this snapshot.\nfunc (sd *snapshotData) getProgram(projectHandle ProjectID) (*compiler.Program, error) {\n\tproj, err := sd.getProject(projectHandle)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tprogram := proj.GetProgram()\n\tif program == nil {\n\t\treturn nil, fmt.Errorf(\"%w: project has no program\", ErrClientError)\n\t}\n\n\treturn program, nil\n}\n\n// getProject looks up a project from a project handle within this snapshot.\nfunc (sd *snapshotData) getProject(projectHandle ProjectID) (*project.Project, error) {\n\tprojectName := parseProjectHandle(projectHandle)\n\tproj := sd.snapshot.ProjectCollection.GetProjectByPath(projectName)\n\tif proj == nil {\n\t\treturn nil, fmt.Errorf(\"%w: project %s not found\", ErrClientError, projectName)\n\t}\n\treturn proj, nil\n}\n\n// nodeHandleFrom creates an index-based node handle (index.kind.path), building a node index table\n// for the file on-demand if needed.\nfunc (sd *snapshotData) nodeHandleFrom(node *ast.Node) NodeHandle {","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/api/session.go#L68-L104","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst res = await call(\"getTypeAtPosition\", { snapshot, project, file, position }); // project has no program\n\n// after\nconst proj = await call(\"getDefaultProjectForFile\", { snapshot, file }); // project that loaded `file`\nif (proj) {\n  const res = await call(\"getTypeAtPosition\", { snapshot, project: proj, file, position });\n}","handlingStrategy":"validation","validationCode":"// TS client: confirm the project actually loaded files before checker calls.\nconst names = await call(\"getSourceFileNames\", { snapshot, project });\nif (!names || names.length === 0) {\n  throw new Error(`project ${project} has no loaded files - program not built; check its tsconfig`);\n}\n// only now issue getTypeAtPosition / getSignaturesOfType / ...","typeGuard":null,"tryCatchPattern":"try {\n  return await call(method, params);\n} catch (e) {\n  if (String(e).includes(\"project has no program\")) {\n    // config likely broken: re-open the project's files via updateSnapshot,\n    // validate tsconfig via parseConfigFile, then retry once with the fresh handle\n    const fresh = await reopenProject(file);\n    return await call(method, { ...params, snapshot: fresh.snapshot, project: fresh.project });\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["project","program","compiler","tsconfig","lifecycle","client-error"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}