Context
Migrating an Actor to v4.
Which package is this bug report for?
@crawlee/core
Issue description
KeyValueStore.getPublicUrl() does not see a record written in the current storage transaction.
Inside a transaction, setValue() buffers the write in the transaction journal. getValue() correctly reads that buffered value, but getPublicUrl() goes directly to the storage backend, where the record does not exist until the transaction commits.
This contradicts the documented transaction behavior that reads inside a handler see their own writes:
https://crawlee.dev/js/docs/next/upgrading/upgrading-to-v4#storage-writes-in-request-handlers-are-transactional
The current implementation bypasses the transaction entirely:
|
async getPublicUrl(key: string): Promise<string | undefined> { |
|
return this.backend.getPublicUrl(key); |
|
} |
This breaks the common pattern of storing a file in KVS and including its URL in a dataset item from the same request handler:
await keyValueStore.setValue(key, html, { contentType: 'text/html' });
await pushData({
htmlUrl: await keyValueStore.getPublicUrl(key),
});
htmlUrl is undefined, even though the record is successfully created when the handler's transaction commits.
Code sample
import { randomUUID } from 'node:crypto';
import { KeyValueStore, withStorageTransaction } from '@crawlee/core';
const store = await KeyValueStore.open({
name: `get-public-url-transaction-${randomUUID()}`,
});
const key = 'record';
await withStorageTransaction(async () => {
await store.setValue(key, 'value', {
contentType: 'text/plain',
});
console.log('value inside:', await store.getValue(key));
console.log('URL inside:', await store.getPublicUrl(key));
});
console.log('URL after commit:', await store.getPublicUrl(key));
Output:
value inside: value
URL inside: undefined
URL after commit: file:///.../key_value_stores/get-public-url-transaction-.../record
Expected output:
value inside: value
URL inside: file:///.../record
URL after commit: file:///.../record
Package version
@crawlee/core@4.0.0-rc.0
Node.js version
v24.15.0, TypeScript 5.9.3
Operating system
macOS 26.2 (arm64)
Apify platform
unticked
Context
Migrating an Actor to v4.
Which package is this bug report for?
@crawlee/core
Issue description
KeyValueStore.getPublicUrl()does not see a record written in the current storage transaction.Inside a transaction,
setValue()buffers the write in the transaction journal.getValue()correctly reads that buffered value, butgetPublicUrl()goes directly to the storage backend, where the record does not exist until the transaction commits.This contradicts the documented transaction behavior that reads inside a handler see their own writes:
https://crawlee.dev/js/docs/next/upgrading/upgrading-to-v4#storage-writes-in-request-handlers-are-transactional
The current implementation bypasses the transaction entirely:
crawlee/packages/core/src/storages/key_value_store.ts
Lines 786 to 788 in cceca28
This breaks the common pattern of storing a file in KVS and including its URL in a dataset item from the same request handler:
htmlUrlisundefined, even though the record is successfully created when the handler's transaction commits.Code sample
Output:
Expected output:
Package version
@crawlee/core@4.0.0-rc.0
Node.js version
v24.15.0, TypeScript 5.9.3
Operating system
macOS 26.2 (arm64)
Apify platform
unticked