From 9a9471bfb2d5d55955c8041118a837c39dd9143d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hanu=C5=A1?= Date: Thu, 2 Jul 2026 00:28:13 +0200 Subject: [PATCH] feat(push): validate actor.json version against MAJOR.MINOR before upload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The platform's version field is MAJOR.MINOR (e.g. `0.0`, `1.2`) and rejects three-part SemVer like `1.0.0`. Today that mistake is only caught during the remote build admission step, after the source files are already uploaded and a build slot is spent — the error surface is cryptic and every retry burns a build. Add a small client-side guard in `apify push` that reads the effective `version` (flag override, then actor.json, then default) and fails fast with a clear message pointing at the field. Regex is defined locally as a TODO placeholder until the shared version in apify-shared-js #655 lands; the intent is to swap in the shared export in a follow-up. Co-Authored-By: Claude Opus 4.7 --- src/commands/actors/push.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/commands/actors/push.ts b/src/commands/actors/push.ts index 683462834..030cf01b3 100644 --- a/src/commands/actors/push.ts +++ b/src/commands/actors/push.ts @@ -42,6 +42,11 @@ const DEFAULT_RUN_OPTIONS = { }; const DEFAULT_ACTOR_VERSION_NUMBER = '0.0'; +// Actor versions on the platform are MAJOR.MINOR (both non-negative integers). +// TODO: import from @apify/consts / apify-shared-js once the shared regex lands +// (see apify-shared-js #655). +const MAJOR_MINOR_VERSION_REGEX = /^(0|[1-9]\d*)\.(0|[1-9]\d*)$/; + // It would be better to use `version-0.0` or similar, // or even have no default tag, but the platform complains when // Actor does not have a build with a `latest` tag, so until @@ -249,6 +254,22 @@ export class ActorsPushCommand extends ApifyCommand { const { config: actorConfig } = actorConfigResult.unwrap(); + // Client-side guard: the platform rejects `.version` values that are not + // exactly MAJOR.MINOR (e.g. `1.0.0` fails during the build step with a + // cryptic admission error). Catch it here so agents/users get a fast, + // actionable message pointing at the field. + const rawVersion = (actorConfig?.version as string | undefined) ?? this.flags.version; + if (rawVersion !== undefined && !MAJOR_MINOR_VERSION_REGEX.test(rawVersion)) { + error({ + message: + `Invalid Actor version '${rawVersion}' in ${LOCAL_CONFIG_PATH}. ` + + `Actor versions must be MAJOR.MINOR (e.g. "0.0", "1.2") — patch versions like "1.0.0" are not supported. ` + + `Fix the \`version\` field in ${LOCAL_CONFIG_PATH} and retry.`, + }); + process.exitCode = CommandExitCodes.InvalidActorJson; + return; + } + const userInfo = await getLocalUserInfo(); const isOrganizationLoggedIn = !!userInfo.organizationOwnerUserId; const redirectUrlPart = isOrganizationLoggedIn ? `/organization/${userInfo.id}` : '';