hcengineering/platform · error · PlatformError

No AdapterManager

Error message

No AdapterManager

What it means

LowLevel middleware's static create() requires an AdapterManager on the pipeline context because it builds low-level storage access (find/insert/delete across domain adapters) from it. If context.adapterManager is null/undefined it throws a PlatformError with the unknownStatus 'No AdapterManager'.

Source

Thrown at foundations/server/packages/middleware/src/lowLevel.ts:42

  type Ref,
  type StorageIterator
} from '@hcengineering/core'
import { PlatformError, unknownStatus } from '@hcengineering/platform'
import type { Middleware, PipelineContext } from '@hcengineering/server-core'
import { BaseMiddleware } from '@hcengineering/server-core'

/**
 * Will perform a find inside adapters
 * @public
 */
export class LowLevelMiddleware extends BaseMiddleware implements Middleware {
  static async create (
    ctx: MeasureContext,
    context: PipelineContext,
    next: Middleware | undefined
  ): Promise<Middleware | undefined> {
    if (context.adapterManager == null) {
      throw new PlatformError(unknownStatus('No AdapterManager'))
    }
    const adapterManager = context.adapterManager
    context.lowLevelStorage = {
      find (ctx: MeasureContext, domain: Domain): StorageIterator {
        return adapterManager.getAdapter(domain, false).find(ctx, domain)
      },

      load (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<Doc[]> {
        return adapterManager.getAdapter(domain, false).load(ctx, domain, docs)
      },

      upload (ctx: MeasureContext, domain: Domain, docs: Doc[]): Promise<void> {
        return adapterManager.getAdapter(domain, true).upload(ctx, domain, docs)
      },

      clean (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<void> {
        return adapterManager.getAdapter(domain, true).clean(ctx, domain, docs)
      },

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Configure context.adapterManager (add the adapter-manager middleware) before LowLevel.create() in the pipeline
  2. Check the pipeline factory/order so the AdapterManager middleware runs before LowLevel
  3. Verify server configuration supplies the storage/adapter settings used to build the AdapterManager

Example fix

// before
const pipeline = await Pipeline.create(ctx, context, [LowLevel.create, ...]) // context.adapterManager undefined
// after
context.adapterManager = new AdapterManager(ctx, storageConfig)
const pipeline = await Pipeline.create(ctx, context, [AdapterManager.create, LowLevel.create, ...])
Defensive patterns

Strategy: validation

Validate before calling

if (context.adapterManager == null) {
  throw new Error('AdapterManager must be configured before LowLevel.create')
}

Type guard

function hasAdapterManager(ctx: PipelineContext): ctx is PipelineContext & { adapterManager: AdapterManager } {
  return ctx.adapterManager != null
}

Try / catch

try {
  await LowLevel.create(ctx, context, next)
} catch (err) {
  if (isPlatformErrorWith(err, 'No AdapterManager')) {
    throw new Error('pipeline misconfigured: register AdapterManager middleware')
  }
  throw err
}

Prevention

When it happens

Trigger: Constructing the pipeline with LowLevel.create() while the PipelineContext was built without an adapterManager (e.g. adapter manager middleware not added or context assembled manually).

Common situations: Missing configuration when assembling the middleware pipeline; forgetting to register the adapterManager middleware before lowLevel; custom pipeline construction that omits context.adapterManager; service bootstrap missing DB adapter configuration.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/769fe9072e215f5c. Report an issue: GitHub.