Skip to content

Critical Bug: getService Throws for Async Factory Services ('auth', 'analytics') — Kernel/Dispatcher/Adapters must resolve async services #858

Description

@hotlong

Synchronous getService Error for Async Auth & Analytics Services

Problem Statement

Calling getService('analytics') or getService('auth') via the ObjectStack Kernel (ObjectKernel/LiteKernel) throws the following runtime error if the service was registered with an async factory:

Error: Service 'analytics' is async - use await
Error: Service 'auth' is async - use await

Impacted Components

  • packages/runtime/src/http-dispatcher.ts — Dispatcher uses private getService() which calls sync kernel.getService()
  • Kernel & Dispatcher call chain (dispatcher.handleAnalytics, dispatcher.handleAuth)
  • All adapter plugins (Fastify, Hono, Next.js, SvelteKit, NestJS) that rely on kernel.getService('auth') or kernel.getService('analytics')
  • Plugins/services registered via async factory (e.g. PluginLoader)

Root Cause

  • getService() uses the synchronous path but some services (auth, analytics) were registered as async factories (via dependency injection in PluginLoader).
  • When the service lookup resolves to a Promise, kernel throws to avoid returning a Promise from a sync API.
  • Dispatcher and adapters frequently use sync getService, which breaks if consumers are not migrated to async path.

Code Evidence

  • kernel.ts: Throws when service is async but called via sync API.
  • http-dispatcher.ts: Dispatcher sync service lookup fails for async services.
  • Service interfaces (IAnalyticsService, IAuthService) are Promise-based, and actual plugin implementations often use async factories for setup.
  • Test files simulate both sync and async scenarios (see *.test.ts for dispatcher, adapters).

Solution Proposal

  • Refactor http-dispatcher.ts and all adapters:
    • Use an explicit getServiceAsync() method for service registry lookup when factory-based services are possible.
    • Ensure dispatcher.handleAuth and dispatcher.handleAnalytics always resolve services asynchronously.
    • Adapters must also use async resolution for service lookup instead of kernel's synchronous getService().
  • Best Practice: Consider deprecating direct getService() access for any service interface defined as Promise-based, or add documentation warnings in ObjectStack Kernel and Adapter docs.

Priority

  • High: Breaks dispatch and dynamic service composition for any plugin using async registration.

References & Context

  • ObjectStack repo: spec
  • Multiple test examples show async mocks (passing) but production sync lookups fail.

Root cause & solution verified. Please prioritize and coordinate adapter refactor/migration.

/cc @hotlong @objectstack-ai


(Merged: covers both analytics & auth, all adapters, and dispatcher)

Metadata

Metadata

Labels

bugSomething isn't working

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions