hcengineering/platform · error · PlatformError

Low level storage is not available

Error message

Low level storage is not available

What it means

BackupClient.getOps lazily creates a BackupClientOps wrapper around pipeline.context.lowLevelStorage. If the pipeline context has no lowLevelStorage (undefined), backup/restore operations cannot talk to the underlying storage, so a PlatformError(unknownError(...)) is thrown.

Source

Thrown at foundations/server/packages/server/src/client.ts:355

      }
      const bevent = createBroadcastEvent(Array.from(classes))
      void socket.send(
        ctx,
        {
          result: [bevent]
        },
        this.binaryMode,
        this.useCompression
      )
    } else {
      void socket.send(ctx, { result: tx }, this.binaryMode, this.useCompression)
    }
  }

  getOps (pipeline: Pipeline): BackupClientOps {
    if (this.ops === undefined || this.opsPipeline !== pipeline) {
      if (pipeline.context.lowLevelStorage === undefined) {
        throw new PlatformError(unknownError('Low level storage is not available'))
      }
      this.ops = new BackupClientOps(pipeline.context.lowLevelStorage)
      this.opsPipeline = pipeline
    }
    return this.ops
  }

  async loadChunk (ctx: ClientSessionCtx, domain: Domain, idx?: number): Promise<void> {
    this.lastRequest = Date.now()
    try {
      const result = await this.getOps(ctx.pipeline).loadChunk(ctx.ctx, domain, idx)
      await ctx.sendResponse(ctx.requestId, result)
    } catch (err: any) {
      await ctx.sendError(ctx.requestId, 'Failed to upload', unknownError(err))
      ctx.ctx.error('failed to loadChunk', { domain, err })
    }
  }

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Ensure the pipeline context is initialized with a lowLevelStorage before using BackupClient
  2. Fix the storage configuration so createStorageFromConfig produces an adapter and it is assigned to context.lowLevelStorage
  3. Guard backup entry points to check context.lowLevelStorage first and fail with a clear config error

Example fix

// before
client.upload(pipeline, data)
// after
if (pipeline.context.lowLevelStorage === undefined) {
  throw new Error('Backup unavailable: storage not configured for this pipeline')
}
client.upload(pipeline, data)
Defensive patterns

Strategy: validation

Validate before calling

function assertBackupReady(pipeline) {
  if (pipeline?.context?.lowLevelStorage === undefined) {
    throw new Error('Backup requires a pipeline initialized with a lowLevelStorage adapter')
  }
}

Type guard

function hasLowLevelStorage(pipeline) {
  return pipeline != null && pipeline.context != null &&
    pipeline.context.lowLevelStorage !== undefined
}

Try / catch

import { PlatformError } from '@hcengineering/platform'
try {
  await backupClient.upload(pipeline, data)
} catch (e) {
  if (e instanceof PlatformError && e.message.includes('Low level storage is not available')) {
    throw new Error('Storage misconfigured: pipeline has no lowLevelStorage; fix storage config before backup')
  }
  throw e
}

Prevention

When it happens

Trigger: Invoking backup operations (via result, closeChunk, upload or clean paths) on a pipeline whose context was built without a lowLevelStorage adapter — e.g. storage not initialized or the pipeline was created before storage adapters were attached.

Common situations: Running backup tooling against a workspace/pipeline that lacks storage binding; server started with storage misconfigured so lowLevelStorage never got assigned; calling backup API before pipeline initialization completes.

Related errors


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