{"record":{"id":"0fd8d12c81e48709","repo":"hcengineering/platform","slug":"direct-blob-operations-are-not-possible","errorCode":null,"errorMessage":"Direct Blob operations are not possible","messagePattern":"Direct Blob operations are not possible","errorType":"exception","errorClass":"PlatformError","httpStatus":null,"severity":"error","filePath":"server/server-pipeline/src/blobStorage.ts","lineNumber":111,"sourceCode":"  ): Promise<void> {}\n\n  async rawDeleteMany<T extends Doc>(domain: Domain, query: DocumentQuery<T>): Promise<void> {}\n\n  async findAll<T extends Doc>(\n    ctx: MeasureContext,\n    _class: Ref<Class<T>>,\n    query: DocumentQuery<T>,\n    options?: FindOptions<T>\n  ): Promise<FindResult<T>> {\n    return toFindResult([])\n  }\n\n  async groupBy<T>(ctx: MeasureContext, domain: Domain, field: string): Promise<Map<T, number>> {\n    return new Map()\n  }\n\n  async tx (ctx: MeasureContext, ...tx: Tx[]): Promise<TxResult[]> {\n    throw new PlatformError(unknownError('Direct Blob operations are not possible'))\n  }\n\n  async createIndexes (domain: Domain, config: Pick<IndexingConfiguration<Doc>, 'indexes'>): Promise<void> {}\n  async removeOldIndex (domain: Domain, deletePattern: RegExp[], keepPattern: RegExp[]): Promise<void> {}\n\n  async close (): Promise<void> {}\n\n  find (ctx: MeasureContext, domain: Domain): StorageIterator {\n    return this.client.find(ctx, this.storageIds)\n  }\n\n  async load (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<Doc[]> {\n    const blobs: Blob[] = []\n    for (const d of docs) {\n      const bb = await this.client.stat(ctx, this.storageIds, d)\n      if (bb !== undefined) {\n        blobs.push(bb)\n      }","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/server/server-pipeline/src/blobStorage.ts#L93-L129","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Remove the code path that routes document Tx to the blob storage adapter; use its upload/download API instead.","Check adapterManager configuration so the affected domain maps to a real DB adapter (e.g. the PostgreSQL/DbAdapter), not blob storage.","If this happens during upgrade/indexing, filter out the blob storage domain/adapter before applying transactions."],"exampleFix":"// before\nawait blobAdapter.tx(ctx, tx)\n// after\nconst adapter = adapterManager.getAdapter(domain, false)\nawait adapter.tx(ctx, tx) // real DB adapter, not blob storage","handlingStrategy":"try-catch","validationCode":"const adapter = adapterManager.getAdapter(domain, false)\nif (adapter === undefined || adapter instanceof BlobStorageAdapter /* blob adapter */) {\n  throw new Error(`Domain ${domain} is not transactional (blob storage)`)\n}","typeGuard":"function isTransactionalAdapter(a: TxAdapter | undefined): a is TxAdapter {\n  return a !== undefined && !(a as { groupBy?: unknown }).constructor.name.includes('Blob')\n}","tryCatchPattern":"try {\n  await adapter.tx(ctx, ...txs)\n} catch (err) {\n  if ((err as Error).message.includes('Direct Blob operations are not possible')) {\n    // route txs to the DB adapter or use blob upload API instead\n    return\n  }\n  throw err\n}","preventionTips":["Never call tx() on the blob storage adapter; use its upload/download methods.","Verify domain→adapter mappings before routing transactions.","Exclude blob-storage domains from generic Tx processing loops and upgrade tooling."],"tags":["blob-storage","transactions","unsupported-operation"],"backgroundTag":"unsupported-adapter-operation","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}