microsoft/typescript-go · error · ErrClientError

%w: type handle %d not found (no registry for project %s)

Error message

%w: type handle %d not found (no registry for project %s)

What it means

resolveTypeHandle found no projectRegistryData for the given ProjectID, reported as "type handle N not found (no registry for project P)". A project's type registry is created lazily the first time a type response is registered in that project within this snapshot, so 'no registry' means no type-returning call has ever produced types for this project here - in practice the ProjectID is wrong or stale for this snapshot.

Source

Thrown at internal/api/session.go:266

	return symbol, nil
}

// resolveTypeHandle resolves a type handle within the project's registry.
func (sd *snapshotData) resolveTypeHandle(projectID ProjectID, handle TypeID) (*checker.Type, error) {
	if handle == 0 {
		return nil, fmt.Errorf("%w: empty type handle", ErrClientError)
	}
	if projectID == "" {
		return nil, fmt.Errorf("%w: empty project ID for type handle %d", ErrClientError, handle)
	}

	sd.projectRegistriesMu.RLock()
	reg := sd.projectRegistries[projectID]
	sd.projectRegistriesMu.RUnlock()

	if reg == nil {
		return nil, fmt.Errorf("%w: type handle %d not found (no registry for project %s)", ErrClientError, handle, projectID)
	}

	reg.typeRegistryMu.RLock()
	t, ok := reg.typeRegistry[handle]
	reg.typeRegistryMu.RUnlock()

	if !ok {
		return nil, fmt.Errorf("%w: type handle %d not found in project registry", ErrClientError, handle)
	}

	return t, nil
}

// resolveSignatureHandle resolves a signature handle within the project's registry.
func (sd *snapshotData) resolveSignatureHandle(projectID ProjectID, handle SignatureID) (*checker.Signature, error) {
	if handle == 0 {
		return nil, fmt.Errorf("%w: empty signature handle", ErrClientError)
	}

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Re-fetch the type in the current snapshot before querying its sub-properties
  2. Keep project, snapshot, and type id together as one unit; invalidate the whole unit on snapshot change
  3. Verify the project handle itself still resolves (a wrong project path also produces this error)

Example fix

// before
await call("getTypesOfType", { snapshot, project: oldProject, type: cachedTypeId }); // no registry

// after
const sym = await call("getSymbolAtPosition", { snapshot, project, file, position });
const t = sym && await call("getTypeOfSymbol", { snapshot, project, symbol: sym.id });
if (t) await call("getTypesOfType", { snapshot, project, type: t.id });
Defensive patterns

Strategy: validation

Validate before calling

// TS client: validate scope before the request.
const key = `${snapshot}:${project}`;
if (!typeRegistriesSeen.has(key)) {
  // no type-producing call has run for this project in this snapshot;
  // a type handle claimed to come from there is stale or mismatched
  throw new Error(`no type registry for ${key}; re-acquire the type via getTypeOfSymbol/getTypeAtPosition`);
}

Type guard

const isScopedTypeHandle = (h: { snapshot: bigint; project: string; id: number }, cur: bigint): boolean =>
  h.snapshot === cur && h.project.length > 0 && h.id > 0;

Prevention

When it happens

Trigger: Sending a type handle with a project handle from a different snapshot (registries are snapshot-scoped); mixing handles: type id from project A paired with project B's handle; a project that legitimately has no registered types yet being queried with a fabricated type id.

Common situations: Client caches {project, type} pairs across updateSnapshot cycles; monorepo clients routing queries between sibling projects and swapping ids; session restart wiping registries while the client kept its handle table.

Related errors


AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16). Data as JSON: /api/errors/812c1de5cda0d0dc. Report an issue: GitHub.