Skip to content

docs(openapi): Autofix OpenAPI spec validation errors#2403

Open
Pijukatel wants to merge 11 commits intomasterfrom
claude/fix-openapi-autofixes-U0Wy4
Open

docs(openapi): Autofix OpenAPI spec validation errors#2403
Pijukatel wants to merge 11 commits intomasterfrom
claude/fix-openapi-autofixes-U0Wy4

Conversation

@Pijukatel
Copy link
Copy Markdown
Contributor

@Pijukatel Pijukatel commented Apr 8, 2026

Summary

Autogenerated OpenAPI fixes suggestions based on validation errors generated from running API integration tests with OpenAPI validator turned on.

Error log: https://apify-pr-test-env-logs.s3.us-east-1.amazonaws.com/apify/apify-core/26280/api-e8976db3b5b2476d2f01af1a84d4268fc61e839f.log

apify-core version: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f

Stop reason: No new fixes possible. All remaining validation errors are deliberate negative tests, known false positives (nullable date-time fields), validator limitations (oneOf for KV store records), missing endpoints (out of scope), or global middleware artifacts (method query parameter override). 16 unique error types fixed out of 20 target.

Detailed changes description

Error fixes

1. Fix pricingInfo oneOf validation errors

  • Files: components/schemas/actor-pricing-info/FreeActorPricingInfo.yaml, PayPerEventActorPricingInfo.yaml, PricePerDatasetItemActorPricingInfo.yaml, FlatPricePerMonthActorPricingInfo.yaml
  • Error: must have required property 'pricePerUnitUsd' / must have required property 'pricingPerEvent' / must have required property 'trialMinutes' / must have required property 'unitName' at GET/PUT /v2/acts/{actorId}
  • Root cause: The pricingInfo oneOf schemas had mismatched required fields. Each pricing model type had required fields that don't exist for that model (e.g., FREE model doesn't have pricePerUnitUsd). Inlined the pricingModel enum values to each schema so the validator can discriminate correctly.
  • Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/packages/actor/src/pricing/pricing.both.ts#L22

2. Fix maxItems type in RunOptions

3. Fix version DELETE 404 error type

4. Fix sourceFiles required fields

5. Fix RequestUrl format:uri on SharedProperties

6. Fix unsupported media type errors on run endpoints

  • Files: paths/actors/acts@{actorId}@runs.yaml, acts@{actorId}@run-sync.yaml, acts@{actorId}@run-sync-get-dataset-items.yaml, paths/actor-tasks/actor-tasks@{actorTaskId}@runs.yaml, actor-tasks@{actorTaskId}@run-sync.yaml, actor-tasks@{actorTaskId}@run-sync-get-dataset-items.yaml
  • Error: unsupported media type undefined at POST on all 6 run endpoints
  • Root cause: The run endpoints use BODY_PARSER_TYPES.raw with type: () => true which accepts ANY content type. The spec only declared application/json content type. Added "*/*": schema: {} wildcard to requestBody content.
  • Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/api/src/middleware/body_parser.ts#L61

7. Fix CreateTaskRequest required name field

8. Fix missing waitForFinish parameter on actors runs/last

9. Fix webhook requestUrl format:uri

10. Fix request queue payload type

11. Fix status query parameter serialization

12. Fix filter query parameter serialization

13. Fix startedAfter/startedBefore reserved character handling

14. Fix missing waitForFinish parameter on actor-tasks runs/last

15. Fix Content-Encoding enum missing identity value

16. Fix missing view parameter on run-sync-get-dataset-items endpoints

  • Files: paths/actors/acts@{actorId}@run-sync-get-dataset-items.yaml, paths/actor-tasks/actor-tasks@{actorTaskId}@run-sync-get-dataset-items.yaml, components/parameters/datasetItemsParameters.yaml
  • Error: Unknown query parameter 'view' at POST /v2/acts/{actorId}/run-sync-get-dataset-items and POST /v2/actor-tasks/{actorTaskId}/run-sync-get-dataset-items
  • Root cause: The run-sync-get-dataset-items endpoints call respondWithDatasetItemsStream() which processes the view query parameter (at datasets.ts:328), but the spec was missing this parameter. Also extracted the inline view parameter from datasets@{datasetId}@items.yaml into a reusable component in datasetItemsParameters.yaml.
  • Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/api/src/routes/actors/run_sync_dataset.ts#L57

Refactoring

Extract view parameter to reusable component

  • Files: components/parameters/datasetItemsParameters.yaml, paths/datasets/datasets@{datasetId}@items.yaml
  • Moved the inline view parameter definition from the dataset items endpoint into the shared datasetItemsParameters.yaml file. This follows the apify-docs guideline to prefer $ref reuse over duplication, and enables the fix for run-sync-get-dataset-items endpoints.

Replace single-item enums with const

  • Files: components/schemas/actor-pricing-info/PayPerEventActorPricingInfo.yaml:11, FreeActorPricingInfo.yaml:10, PricePerDatasetItemActorPricingInfo.yaml:12, FlatPricePerMonthActorPricingInfo.yaml:12, paths/request-queues/request-queues@{queueId}@requests@batch.yaml:95
  • Per reviewer feedback and updated AGENTS.md syntax hints, replaced all single-item enum definitions with const (OpenAPI 3.1 syntax). Affects 4 pricingModel discriminator fields and 1 Content-Type header parameter.

AGENTS.md syntax hints update

  • Files: AGENTS.md
  • Maintainer commit (cb46377) adding const syntax hints to the OpenAPI specification changes section. This motivated the enum-to-const refactoring above.

Unfixed errors

False positives

Nullable date-time fields in taggedBuilds

Nullable date-time fields in lastDispatch

Handler mutation of input field (anyOf)

KV store record oneOf response validation

Out of scope errors

Missing actor-runs sub-route endpoints

  • Error: not found at GET /v2/actor-runs/{runId}/log, /v2/actor-runs/{runId}/dataset, /v2/actor-runs/{runId}/key-value-store, /v2/actor-runs/{runId}/request-queue (~277 occurrences)
  • Root cause: These endpoints exist in the API but are not defined in the OpenAPI spec. Adding new endpoints is out of scope for this PR.

Missing validate-input endpoint

  • Error: not found at POST /v2/acts/{actorId}/validate-input (~46 occurrences)
  • Root cause: This endpoint exists in the API but is not defined in the OpenAPI spec. Adding new endpoints is out of scope.

Global method query parameter override

  • Error: Unknown query parameter 'method' on various endpoints (~4 occurrences)
  • Root cause: The API has a global middleware (overrideMethodMiddleware) that accepts ?method= on every endpoint to override the HTTP method. This is a cross-cutting transport-level concern, not a per-endpoint parameter. Not appropriate to add to every endpoint in the spec.

Potential API bugs

None identified.

Issues

Partially implements: #2286

claude added 2 commits April 8, 2026 12:26
…e, and record response schema

Error: WARN Response OpenAPI validation error {"url":"/v2/acts/{actId}","method":"GET","errors":[{"message":"must match exactly one schema in oneOf","path":"/response/data/pricingInfos/0"}]}
Files: FreeActorPricingInfo.yaml:9, PayPerEventActorPricingInfo.yaml:10, PricePerDatasetItemActorPricingInfo.yaml:10, FlatPricePerMonthActorPricingInfo.yaml:10
Root cause: Each pricing info schema referenced the shared PricingModel enum containing all four values (FREE, PAY_PER_EVENT, PRICE_PER_DATASET_ITEM, FLAT_PRICE_PER_MONTH). This caused FreeActorPricingInfo to match any pricing model since it only requires pricingModel and common fields, violating the oneOf constraint which requires exactly one schema to match.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/packages/types/src/paid_actors.ts#L1

Error: WARN Response OpenAPI validation error {"url":"/v2/acts/{actId}/versions/0.0","method":"DELETE","errors":[{"message":"must be equal to one of the allowed values: actor-not-found","path":"/response/error/type"},{"message":"must be equal to one of the allowed values: record-not-found","path":"/response/error/type"},{"message":"must match exactly one schema in oneOf","path":"/response"}]}
Files: acts@{actorId}@versions@{versionNumber}.yaml:75
Root cause: The 404 response for DELETE version used ActorNotFoundError (enum: actor-not-found) but the API actually returns record-or-token-not-found when the actor is not found or access is denied.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/api/src/lib/actors.ts#L135

Error: WARN Response OpenAPI validation error {"url":"/v2/actor-runs/{runId}/resurrect","method":"POST","errors":[{"message":"must be integer","path":"/response/data/options/maxItems"}]}
Files: RunOptions.yaml:26
Root cause: The maxItems field in RunOptions was defined as type integer but the API can return null when maxItems is not set. The TypeScript type is maxItems?: number which allows the value to be absent or stored as null in MongoDB.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/packages/types/src/actor.ts#L485

Error: WARN Response OpenAPI validation error {"url":"/v2/key-value-stores/{storeId}/records/{recordKey}?attachment=true","method":"GET","errors":[{"message":"must match exactly one schema in oneOf","path":"/response"}]}
Files: RecordResponse.yaml:5
Root cause: RecordResponse was defined as type object with additionalProperties but KV store records can contain any JSON value type (array, string, number, boolean, null), not just objects. Removing the type constraint allows the schema to accept any stored JSON value.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/api/src/lib/key_value_stores.ts#L442
Error: WARN Response OpenAPI validation error {"url":"/v2/key-value-stores/{storeId}/records/{recordKey}?attachment=true","method":"GET","errors":[{"message":"must match exactly one schema in oneOf","path":"/response"}]}
Files: key-value-stores@{storeId}@records@{recordKey}.yaml:41
Root cause: The 200 response defined both application/json (with RecordResponse schema) and */* (with empty schema) content types. The validator creates an internal oneOf between content types, and */* overlaps with application/json causing ambiguous matching. Since KV store records can contain any content type (HTML, text, binary, JSON of any shape), using only */* with an empty schema correctly represents the endpoint behavior without content type ambiguity.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/api/src/lib/key_value_stores.ts#L549
@github-actions github-actions bot added this to the 138th sprint - Tooling team milestone Apr 8, 2026
@github-actions github-actions bot added the t-tooling Issues with this label are in the ownership of the tooling team. label Apr 8, 2026
@apify-service-account
Copy link
Copy Markdown

Preview for this PR was built for commit 1d46f4b and is ready at https://pr-2403.preview.docs.apify.com!

…emove URI format from request URL

Revert: KV store record GET content type removal (false positive - oneOf at /response level is a validator bug)
Error: WARN Response OpenAPI validation error {"url":"/v2/acts","method":"POST","errors":[{"message":"must have required property 'format'"}]}
Files: components/schemas/actors/SourceCodeFile.yaml:3
Root cause: SourceCodeFile schema required format and content, but backend schema marks both as optional with defaults
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/packages/actor/src/actors/actors.both.ts#L272

Error: WARN Response OpenAPI validation error {"url":"/v2/request-queues/{queueId}/head/lock","errors":[{"message":"must match format \"uri\""}]}
Files: components/schemas/request-queues/SharedProperties.yaml:18
Root cause: RequestUrl had format: uri but backend does not validate URLs as URIs
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/packages/schemas/src/request_queues.ts#L27
@apify-service-account
Copy link
Copy Markdown

Preview for this PR was built for commit dbf3175 and is ready at https://pr-2403.preview.docs.apify.com!

…tion, and type constraints

Error: unsupported media type application/x-www-form-urlencoded at /v2/acts/{actorId}/runs and 5 other run endpoints
Files: paths/actors/acts@{actorId}@runs.yaml:114, paths/actors/acts@{actorId}@run-sync.yaml:40, paths/actors/acts@{actorId}@run-sync-get-dataset-items.yaml:63, paths/actor-tasks/actor-tasks@{actorTaskId}@runs.yaml:105, paths/actor-tasks/actor-tasks@{actorTaskId}@run-sync.yaml:40, paths/actor-tasks/actor-tasks@{actorTaskId}@run-sync-get-dataset-items.yaml:63
Root cause: These endpoints use BODY_PARSER_TYPES.raw which accepts any content type via type: () => true. The spec only declared application/json but needs wildcard */* to match actual API behavior.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/api/src/middleware/body_parser.ts#L61

Error: must have required property 'name' at POST /v2/actor-tasks
Files: components/schemas/actor-tasks/CreateTaskRequest.yaml:3
Root cause: Backend auto-generates task name if not provided (createActorTask generates name from actor name + random suffix).
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/packages/actor-server/src/actor_tasks/actor_tasks.server.ts#L417

Error: Unknown query parameter 'waitForFinish' at GET /v2/acts/{actorId}/runs/last
Files: paths/actors/acts@{actorId}@Runs@last.yaml:63
Root cause: The runs/last endpoint supports the same parameters as the run object endpoint, including waitForFinish.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/api/src/routes/routes_config.ts#L369

Error: must match format "uri" at POST /v2/webhooks for requestUrl
Files: components/schemas/webhooks/WebhookCreate.yaml:29
Root cause: Backend validates webhook requestUrl using custom WEBHOOK_REQUEST_URL_REGEXP (HTTP_URL_REGEX | LOCALHOST_URL_REGEXP), not strict URI format.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/packages/consts/src/webhooks.ts#L31

Error: must be object,null for payload at POST /v2/request-queues/{queueId}/requests/batch
Files: components/schemas/request-queues/RequestBase.yaml:18
Root cause: Backend request queue schema defines payload as SimpleSchema.oneOf(String, Object) on client side, accepting both string and object types.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/packages/schemas/src/request_queues.ts#L40

Error: Parameter 'status' must be url encoded - reserved characters at GET /v2/acts/{actorId}/runs
Files: components/parameters/runAndBuildParameters.yaml:254
Root cause: API accepts comma-separated status values (e.g. ?status=SUCCEEDED,ABORTED). Changed to array type with explode:false to properly model comma-separated serialization.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/api/src/routes/actors/act_run_list.ts#L1

Error: Parameter 'filter' must be url encoded - reserved characters at GET /v2/request-queues/{queueId}/requests
Files: paths/request-queues/request-queues@{queueId}@requests.yaml:38
Root cause: API accepts comma-separated filter values (e.g. ?filter=pending,locked). Changed to array type with explode:false to properly model comma-separated serialization.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/api/src/routes/request_queues/request_queue_request_list.ts#L1

Error: Parameter 'startedAfter' must be url encoded - reserved characters at GET /v2/acts/{actorId}/runs
Files: components/parameters/runAndBuildParameters.yaml:266
Root cause: ISO 8601 datetime strings contain colons which are reserved characters. Added allowReserved:true since the API accepts unencoded datetime strings.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/api/src/routes/actors/act_run_list.ts#L1
@apify-service-account
Copy link
Copy Markdown

Preview for this PR was built for commit 2cc6a7d and is ready at https://pr-2403.preview.docs.apify.com!

…y to Content-Encoding enum

Error: Unknown query parameter 'waitForFinish' at GET /v2/actor-tasks/{actorTaskId}/runs/last
Files: paths/actor-tasks/actor-tasks@{actorTaskId}@Runs@last.yaml:55
Root cause: The actor-tasks runs/last endpoint forwards all query parameters (including waitForFinish) to the actual run endpoint via routeToLastRunRoutes(), same as the actors runs/last endpoint.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/api/src/routes/actor_tasks/last_run.ts#L1

Error: must be equal to one of the allowed values: gzip, deflate, br at PUT /v2/key-value-stores/{storeId}/records/{recordKey}
Files: components/objects/key-value-stores/key-value-stores@{storeId}@records@{recordKey}put.yaml:13
Root cause: The API accepts identity encoding for HTML records (checked at record.ts:102 against [...RECORD_SUPPORTED_ENCODING_TYPES_LIST, IDENTITY_ENCODING_TYPE]). The identity value was missing from the spec's Content-Encoding enum.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/api/src/routes/key_value_stores/record.ts#L102
@apify-service-account
Copy link
Copy Markdown

Preview for this PR was built for commit 84e88e9 and is ready at https://pr-2403.preview.docs.apify.com!

…s endpoints

Error: Unknown query parameter 'view' at POST /v2/acts/{actorId}/run-sync-get-dataset-items and POST /v2/actor-tasks/{actorTaskId}/run-sync-get-dataset-items
Files: paths/actors/acts@{actorId}@run-sync-get-dataset-items.yaml, paths/actor-tasks/actor-tasks@{actorTaskId}@run-sync-get-dataset-items.yaml
Root cause: The run-sync-get-dataset-items endpoints call respondWithDatasetItemsStream() which processes the view query parameter, but the spec was missing this parameter. Also extracted the inline view parameter from datasets@{datasetId}@items.yaml into a reusable component in datasetItemsParameters.yaml.
Reference: https://github.com/apify/apify-core/tree/e8976db3b5b2476d2f01af1a84d4268fc61e839f/src/api/src/routes/actors/run_sync_dataset.ts#L57
@apify-service-account
Copy link
Copy Markdown

Preview for this PR was built for commit 0b907d7 and is ready at https://pr-2403.preview.docs.apify.com!

@apify-service-account
Copy link
Copy Markdown

Preview for this PR was built for commit d7797336 and is ready at https://pr-2403.preview.docs.apify.com!

@apify-service-account
Copy link
Copy Markdown

A PR to update the Python client models has been created: apify/apify-client-python#707

This was automatically triggered by OpenAPI specification changes in this PR.

@apify-service-account
Copy link
Copy Markdown

Preview for this PR was built for commit cb46377f and is ready at https://pr-2403.preview.docs.apify.com!

@apify-service-account
Copy link
Copy Markdown

The Python client model PR has been updated with the latest OpenAPI spec changes: apify/apify-client-python#707

Per reviewer feedback and updated AGENTS.md syntax hints, replace all
single-item enum definitions with const (OpenAPI 3.1 syntax).

Files:
- components/schemas/actor-pricing-info/PayPerEventActorPricingInfo.yaml:11
- components/schemas/actor-pricing-info/FreeActorPricingInfo.yaml:10
- components/schemas/actor-pricing-info/PricePerDatasetItemActorPricingInfo.yaml:12
- components/schemas/actor-pricing-info/FlatPricePerMonthActorPricingInfo.yaml:12
- paths/request-queues/request-queues@{queueId}@requests@batch.yaml:95
@apify-service-account
Copy link
Copy Markdown

Preview for this PR was built for commit 63945b42 and is ready at https://pr-2403.preview.docs.apify.com!

@apify-service-account
Copy link
Copy Markdown

The Python client model PR has been updated with the latest OpenAPI spec changes: apify/apify-client-python#707

@apify-service-account
Copy link
Copy Markdown

Preview for this PR was built for commit c312f9da and is ready at https://pr-2403.preview.docs.apify.com!

@apify-service-account
Copy link
Copy Markdown

The Python client model PR has been updated with the latest OpenAPI spec changes: apify/apify-client-python#707

@Pijukatel Pijukatel requested a review from vdusek April 9, 2026 11:21
@Pijukatel Pijukatel marked this pull request as ready for review April 9, 2026 11:21
Copy link
Copy Markdown
Contributor

@vdusek vdusek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two questions


RequestUrl:
type: string
format: uri
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we removing these format constraints?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that intentional? Perhaps @tobice of @fnesveda could share some thoughts?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably because you might also want to save PseudoURLs to the queue, not just regular URLs. It's been like this since the original implementation: https://github.com/apify/apify-core/commit/9bb347bd4baf62a23bda7c180ce58dd68cf30252#diff-48532f504598f9f0dc62bb5d060e1b3951b95c959d76e797f24e1e6bb155ddebR117

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh hot damn... so will the API really accept any string?

@Pijukatel Pijukatel requested a review from vdusek April 10, 2026 06:07
@apify-service-account
Copy link
Copy Markdown

Preview for this PR was built for commit 775e660c and is ready at https://pr-2403.preview.docs.apify.com!

@apify-service-account
Copy link
Copy Markdown

The Python client model PR has been updated with the latest OpenAPI spec changes: apify/apify-client-python#707

Copy link
Copy Markdown
Member

@fnesveda fnesveda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Copy link
Copy Markdown
Contributor

@janbuchar janbuchar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, provided that we resolve the uri format uncertainty


RequestUrl:
type: string
format: uri
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that intentional? Perhaps @tobice of @fnesveda could share some thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Username table at https://docs.apify.com/proxy/datacenter-proxy is broken

6 participants