Summary
apify actors info <actorId> (the default, human-readable output) throws and exits
1 for Store Actors that use tiered pay-per-event pricing, while working fine for
free Actors and Actors with simpler pricing. The crash is in the pricing renderer,
which reads a flat eventPriceUsd on each charge event and calls .toFixed() on
it — but tiered-priced Actors don't have that field (their prices live under
eventTieredPricingUsd.<TIER>.tieredEventPriceUsd), so it's undefined. The
--input, --readme, and --json flags all work on the same Actors because they
bypass the pricing renderer.
Environment
- apify-cli 1.6.1 (latest on npm at time of filing)
- Reproduced on Node 24.11.1 / Windows x64 and Node 22.22.3 / Linux x64
Steps to reproduce
# crash — tiered pay-per-event Store Actors
npx apify-cli actors info lukaskrivka/google-maps-with-contact-details
npx apify-cli actors info compass/google-maps-reviews-scraper
npx apify-cli actors info apify/google-search-scraper
# works — free Actors
npx apify-cli actors info apify/hello-world
npx apify-cli actors info apify/web-scraper
# works — same paid Actor, pricing renderer bypassed
npx apify-cli actors info lukaskrivka/google-maps-with-contact-details --input
npx apify-cli actors info lukaskrivka/google-maps-with-contact-details --json
Expected
The info card prints for tiered pay-per-event Actors (exit 0), showing the tiered
prices (or skipping the price gracefully when the flat field is absent).
Actual
Error: Cannot read properties of undefined (reading 'toFixed')
Exit code 1, no output.
Root cause (verified)
The affected Actors use pricingModel: "PAY_PER_EVENT" with tiered per-event
pricing. Their charge events have no flat eventPriceUsd; prices are nested under
eventTieredPricingUsd. Verified via apify actors info lukaskrivka/google-maps-with-contact-details --json:
"pricingModel": "PAY_PER_EVENT",
"pricingPerEvent": {
"actorChargeEvents": {
"place-scraped": {
"eventTitle": "Scraped place",
"eventTieredPricingUsd": {
"FREE": { "tieredEventPriceUsd": 0.005 },
"BRONZE": { "tieredEventPriceUsd": 0.004 },
"SILVER": { "tieredEventPriceUsd": 0.003 }
// ... GOLD / PLATINUM / DIAMOND
},
"isPrimaryEvent": true
// NOTE: there is no "eventPriceUsd" key
}
}
}
The pricing renderer (minified in the published 1.6.1 package at
dist/_register-DeIDNArb.js) reads the flat field unguarded:
const events = Object.values(actor.pricingPerEvent?.actorChargeEvents ?? {});
for (const ev of events)
table.pushRow({ [titleCol]: ev.eventTitle, [priceCol]: bold(`$${ev.eventPriceUsd.toFixed(2)}`) });
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ev.eventPriceUsd is undefined for tiered-priced events → "Cannot read properties of undefined (reading 'toFixed')"
So the renderer only handles flat per-event pricing and throws on tiered pricing.
Free Actors don't enter this branch, which is why they don't crash.
Impact
actors info is the primary command for inspecting an Actor, and it fails on
exactly the commercial, tiered-priced Store Actors that real workflows depend on
(e.g. the Google Maps scrapers). Any script or agent that shells out to it gets no
usable output and a non-zero exit.
Workaround
Use --input (input schema), --readme, or --json — all skip the broken pricing
renderer.
Suggested fix
Handle tiered pricing and guard the flat path. For each charge event, prefer
eventTieredPricingUsd when present (render the per-tier prices, or the user's
plan tier / the FREE tier), and fall back to eventPriceUsd only when it is a
number:
const flat = ev.eventPriceUsd;
const tiered = ev.eventTieredPricingUsd;
const price =
typeof flat === "number"
? `$${flat.toFixed(2)}`
: tiered
? `$${(tiered.FREE?.tieredEventPriceUsd ?? 0).toFixed(2)}+ (tiered)`
: "N/A";
The adjacent PRICE_PER_DATASET_ITEM branch (pricePerUnitUsd * 1e3).toFixed(2))
should get the same typeof === "number" guard.
Summary
apify actors info <actorId>(the default, human-readable output) throws and exits1 for Store Actors that use tiered pay-per-event pricing, while working fine for
free Actors and Actors with simpler pricing. The crash is in the pricing renderer,
which reads a flat
eventPriceUsdon each charge event and calls.toFixed()onit — but tiered-priced Actors don't have that field (their prices live under
eventTieredPricingUsd.<TIER>.tieredEventPriceUsd), so it'sundefined. The--input,--readme, and--jsonflags all work on the same Actors because theybypass the pricing renderer.
Environment
Steps to reproduce
Expected
The info card prints for tiered pay-per-event Actors (exit 0), showing the tiered
prices (or skipping the price gracefully when the flat field is absent).
Actual
Exit code 1, no output.
Root cause (verified)
The affected Actors use
pricingModel: "PAY_PER_EVENT"with tiered per-eventpricing. Their charge events have no flat
eventPriceUsd; prices are nested undereventTieredPricingUsd. Verified viaapify actors info lukaskrivka/google-maps-with-contact-details --json:The pricing renderer (minified in the published 1.6.1 package at
dist/_register-DeIDNArb.js) reads the flat field unguarded:So the renderer only handles flat per-event pricing and throws on tiered pricing.
Free Actors don't enter this branch, which is why they don't crash.
Impact
actors infois the primary command for inspecting an Actor, and it fails onexactly the commercial, tiered-priced Store Actors that real workflows depend on
(e.g. the Google Maps scrapers). Any script or agent that shells out to it gets no
usable output and a non-zero exit.
Workaround
Use
--input(input schema),--readme, or--json— all skip the broken pricingrenderer.
Suggested fix
Handle tiered pricing and guard the flat path. For each charge event, prefer
eventTieredPricingUsdwhen present (render the per-tier prices, or the user'splan tier / the FREE tier), and fall back to
eventPriceUsdonly when it is anumber:
The adjacent
PRICE_PER_DATASET_ITEMbranch (pricePerUnitUsd * 1e3).toFixed(2))should get the same
typeof === "number"guard.