Skip to content

KeyValueStore.getPublicUrl() cannot see records buffered by the current storage transaction #4075

Description

@nikitachapovskii-dev

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    t-toolingIssues with this label are in the ownership of the tooling team.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions