Build1 publisher3 min readPublished
A default on a required field turned an empty call into a clean audit of apify.com
Apify's input schema spec says prefill only touches the Console form while default is substituted for any caller that omits the field, and an agent calling through MCP counts as a caller. Seven of one catalogue's nine chainable Actors carried both.
The Engineer · Build desk
What happened
- A developer scripted a read of his own 23 published Apify Actors and counted 61 ordered pairs where one Actor emits the kind of identifier another Actor requires, 36 joined by a URL and 25 by a domain.
- Calling seo-audit-tool from the CLI with an empty input returned an error naming input.urls as required, and the platform created no run at all.
- dataset-to-github-issues requires a dataset ID and a repository name that nothing else in the catalogue emits, leaving it a second stage with no possible first stage.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint A field that is both required and defaulted can never arrive missing, so the required array is not the agent-facing guard on the seven Actors that carry both.
- decision Anyone exposing a tool over MCP now has to pick per field: prefill where the value is only there to populate the Console form, default only where any caller may legitimately skip it.
- contradiction The platform refused the call on the Actor with no default, so the exposure the author went looking for is a line in his own schema and the fix belongs to him.
Substitution happens before validation. That is the only order consistent with both runs [3]. `urls` is in the `required` array of `http-status-checker`, the CLI was handed `{}`, and the run succeeded with `urls` set to `https://apify.com/store` [5][9][10]. Apify's input schema specification names the callers a default applies to: the platform passes the value when the user omits it "via any means (API, CLI, scheduler, or user interface)" [15]. According to the author, an agent calling through the MCP server is one of those means [17].
`prefill` is documented as inert outside the form. It "is only used in the user interface but does not affect the Actor functionality and API", the specification says [13], and, in the same paragraph, "the Prefill value won't be used by existing integrations such as Actor tasks or API calls, but the Default will be if specified" [14]. `seo-audit-tool` carries a prefill of two example URLs on `urls`, and the empty call was still refused [12]. Two settings on one field, and the author says the Console renders them the same [23].
What the experiment failed to show is the useful part. The author set out to prove his 23 published Actors were unsafe for agents to chain, and says the experiment refused [18][1]. The refusal is the first run: the platform named the missing field, created no run, and left no dataset, no compute and no partial result to misread [7][8]. Failing closed is what the platform does when the field has no default, and that default is the only difference between the two calls [11].
The chain count is a property of one catalogue. Nine of the 23 declare a URL or a domain in `required` [3], and the ordered pairs where one Actor emits the identifier another requires come to 36 joined by a URL plus 25 by a domain, which is 61 [4][1]. Seven of the nine carry a default that names a concrete target, and all seven also appear in `required` [5]. That leaves two that stop on an empty input [2]. For a figure like 61 to mean anything on someone else's account, their Actors' outputs have to name the same identifier types their inputs require, and the total tracks pairs rather than Actors.
One Actor has no reachable predecessor. `dataset-to-github-issues` requires a dataset ID and a repository name, and nothing else in the author's catalogue emits either, so no agent can arrive at it from another Actor's output [6]. He says he had not noticed until the script told him [24].
The failure he expected to demonstrate is worth stating in his terms: an agent that drops the value between stages gets no error, the second Actor returns a well-formed dataset, and the answer describes a website the user never asked about [19]. Reading the input the platform stored for a completed run is how you find out what it actually ran on [10]. The author says he has applied a one-line schema fix [20]. Moving a target-naming value from `default` to `prefill` keeps the form populated for humans and leaves the `required` check with work to do [13][14].
What to watch
- Whether Apify's Console or schema validator starts flagging a field that is both required and given a default.
- Whether the Apify MCP server exposes defaults in the tool schema it hands clients, so a calling agent can see the field is optional in practice.
- Whether the author's remaining Actors get the same fix, and how the 61-chain count moves when the URL-emitting outputs change.