{"record":{"id":"9693b1ef54335420","repo":"hcengineering/platform","slug":"low-level-storage-should-be-specified","errorCode":null,"errorMessage":"Low level storage should be specified","messagePattern":"Low level storage should be specified","errorType":"error_code","errorClass":"PlatformError","httpStatus":null,"severity":"error","filePath":"foundations/server/packages/middleware/src/triggers.ts","lineNumber":92,"sourceCode":"  }\n\n  async close (): Promise<void> {\n    clearInterval(this.intervalId)\n  }\n\n  static async create (ctx: MeasureContext, context: PipelineContext, next?: Middleware): Promise<Middleware> {\n    // we need to init triggers from model first.\n    const triggers = new TriggersMiddleware(context, next)\n    await triggers.init(ctx)\n    return triggers\n  }\n\n  async init (ctx: MeasureContext): Promise<void> {\n    if (this.context.storageAdapter == null) {\n      throw new PlatformError(unknownError('Storage adapter should be specified'))\n    }\n    if (this.context.lowLevelStorage == null) {\n      throw new PlatformError(unknownError('Low level storage should be specified'))\n    }\n    this.storageAdapter = this.context.storageAdapter\n    this.triggers.init(this.context.modelDb)\n  }\n\n  async tx (ctx: MeasureContext<SessionData>, tx: Tx[]): Promise<TxMiddlewareResult> {\n    await this.triggers.tx(tx)\n    const result = await this.provideTx(ctx, tx)\n\n    const ftx = filterBroadcastOnly(tx, this.context.hierarchy)\n    if (ftx.length > 0) {\n      await this.processDerived(ctx, ftx)\n    }\n    return result\n  }\n\n  private async processDerived (ctx: MeasureContext<SessionData>, txes: Tx[]): Promise<void> {\n    const findAll: SessionFindAll = async (ctx, _class, query, options) => {","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/foundations/server/packages/middleware/src/triggers.ts#L74-L110","documentation":"Triggers middleware's init() additionally requires context.lowLevelStorage (low-level direct storage access built by the LowLevel middleware). When it is null, init() throws unknownError('Low level storage should be specified').","triggerScenarios":"Calling init()/create() on Triggers middleware when the LowLevel middleware was not part of the pipeline (or ran after), leaving context.lowLevelStorage undefined.","commonSituations":"Pipeline missing the LowLevel middleware; middleware ordering places Triggers before LowLevel; custom context assembly that never populates lowLevelStorage.","solutions":["Add LowLevel middleware (with an AdapterManager configured) before Triggers in the pipeline","Ensure middleware ordering so lowLevelStorage is populated before Triggers.init runs","Verify AdapterManager is configured, since LowLevel.create refuses to build lowLevelStorage without it"],"exampleFix":"// before\nconst pipeline = await Pipeline.create(ctx, context, [Triggers.create]) // no lowLevelStorage\n// after\nconst pipeline = await Pipeline.create(ctx, context, [AdapterManager.create, LowLevel.create, Triggers.create])","handlingStrategy":"validation","validationCode":"if (context.lowLevelStorage == null) {\n  throw new Error('LowLevel middleware must run before Triggers.init')\n}","typeGuard":"function hasLowLevelStorage(ctx: PipelineContext): ctx is PipelineContext & { lowLevelStorage: LowLevelStorage } {\n  return ctx.lowLevelStorage != null\n}","tryCatchPattern":"try {\n  await triggers.init(ctx)\n} catch (err) {\n  if (isPlatformErrorWith(err, 'Low level storage should be specified')) {\n    throw new Error('add LowLevel middleware (with AdapterManager) before Triggers')\n  }\n  throw err\n}","preventionTips":["Always include AdapterManager and LowLevel middleware before Triggers","Enforce middleware ordering conventions in the pipeline factory","Assert context.lowLevelStorage exists before init","Cover full pipeline construction in integration tests"],"tags":["configuration","storage","triggers"],"backgroundTag":"missing-pipeline-dependency","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}