hcengineering/platform · error · PlatformError

Direct Blob operations are not possible

Error message

Direct Blob operations are not possible

What it means

This error is thrown by the blob-storage TxAdapter implementation whenever raw transaction operations (tx/create/update/remove) are attempted directly against blob storage. Blob storage is not a real document domain: it has no transactional object model, so the adapter deliberately refuses all Tx processing. It exists only to provide upload/download helpers alongside the real database adapter in the pipeline.

Source

Thrown at server/server-pipeline/src/blobStorage.ts:111

  ): Promise<void> {}

  async rawDeleteMany<T extends Doc>(domain: Domain, query: DocumentQuery<T>): Promise<void> {}

  async findAll<T extends Doc>(
    ctx: MeasureContext,
    _class: Ref<Class<T>>,
    query: DocumentQuery<T>,
    options?: FindOptions<T>
  ): Promise<FindResult<T>> {
    return toFindResult([])
  }

  async groupBy<T>(ctx: MeasureContext, domain: Domain, field: string): Promise<Map<T, number>> {
    return new Map()
  }

  async tx (ctx: MeasureContext, ...tx: Tx[]): Promise<TxResult[]> {
    throw new PlatformError(unknownError('Direct Blob operations are not possible'))
  }

  async createIndexes (domain: Domain, config: Pick<IndexingConfiguration<Doc>, 'indexes'>): Promise<void> {}
  async removeOldIndex (domain: Domain, deletePattern: RegExp[], keepPattern: RegExp[]): Promise<void> {}

  async close (): Promise<void> {}

  find (ctx: MeasureContext, domain: Domain): StorageIterator {
    return this.client.find(ctx, this.storageIds)
  }

  async load (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<Doc[]> {
    const blobs: Blob[] = []
    for (const d of docs) {
      const bb = await this.client.stat(ctx, this.storageIds, d)
      if (bb !== undefined) {
        blobs.push(bb)
      }

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Remove the code path that routes document Tx to the blob storage adapter; use its upload/download API instead.
  2. Check adapterManager configuration so the affected domain maps to a real DB adapter (e.g. the PostgreSQL/DbAdapter), not blob storage.
  3. If this happens during upgrade/indexing, filter out the blob storage domain/adapter before applying transactions.

Example fix

// before
await blobAdapter.tx(ctx, tx)
// after
const adapter = adapterManager.getAdapter(domain, false)
await adapter.tx(ctx, tx) // real DB adapter, not blob storage
Defensive patterns

Strategy: try-catch

Validate before calling

const adapter = adapterManager.getAdapter(domain, false)
if (adapter === undefined || adapter instanceof BlobStorageAdapter /* blob adapter */) {
  throw new Error(`Domain ${domain} is not transactional (blob storage)`)
}

Type guard

function isTransactionalAdapter(a: TxAdapter | undefined): a is TxAdapter {
  return a !== undefined && !(a as { groupBy?: unknown }).constructor.name.includes('Blob')
}

Try / catch

try {
  await adapter.tx(ctx, ...txs)
} catch (err) {
  if ((err as Error).message.includes('Direct Blob operations are not possible')) {
    // route txs to the DB adapter or use blob upload API instead
    return
  }
  throw err
}

Prevention

When it happens

Trigger: Calling pipeline/blob-storage adapter tx(ctx, ...txs), which is invoked when a TxQueue or transaction processor routes transactions to the blob storage adapter, or when a domain is misconfigured to map onto blob storage and a document change (TxCreate/TxUpdate/TxRemove) is applied to it.

Common situations: A domain incorrectly registered/mapped to the blob storage adapter in the adapter manager; client code obtaining the blob storage adapter directly and calling tx() instead of using the storage upload/download API; generic upgrade/index tooling iterating all adapters and applying transactions to each.

Related errors


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