floci-io/floci · error · AwsException

ValidationException

ValidationException

Error message

PollForThirdPartyJobs requires owner ThirdParty

What it means

Thrown by pollForJobs (CodePipelineService.java:540) when the actionTypeId.owner does not match the polling API: PollForJobs requires owner 'Custom' and PollForThirdPartyJobs requires owner 'ThirdParty'. Any other owner value (AWS, e.g.) fails the guard with ValidationException before any jobs are returned.

Source

Thrown at src/main/java/io/github/hectorvent/floci/services/codepipeline/CodePipelineService.java:540

        String ownerFilter = request.path("actionOwnerFilter").asText(null);
        if (ownerFilter != null) {
            items = items.stream()
                    .filter(i -> ownerFilter.equals(i.getData().path("id").path("owner").asText("Custom")))
                    .toList();
        }
        Page page = page(request, items.size(), 100);
        ObjectNode response = mapper.createObjectNode();
        ArrayNode actionTypes = response.putArray("actionTypes");
        items.subList(page.start(), page.end()).forEach(i -> actionTypes.add(i.getData()));
        addNextToken(response, page, items.size());
        return response;
    }

    private ObjectNode pollForJobs(JsonNode request, String region, String account, boolean thirdParty) {
        JsonNode actionTypeId = request.path("actionTypeId");
        String owner = actionTypeId.path("owner").asText();
        if ((!thirdParty && !"Custom".equals(owner)) || (thirdParty && !"ThirdParty".equals(owner))) {
            throw new AwsException("ValidationException",
                    thirdParty ? "PollForThirdPartyJobs requires owner ThirdParty"
                            : "PollForJobs requires owner Custom", 400);
        }
        String requested = actionTypeId(actionTypeId.path("category").asText(),
                owner, actionTypeId.path("provider").asText(),
                actionTypeId.path("version").asText());
        ArrayNode jobs = mapper.createArrayNode();
        int maximum = Math.max(1, request.path("maxBatchSize").asInt(1));
        for (CodePipelineStoredItem item : items(account, region, "job")) {
            if (jobs.size() >= maximum) {
                break;
            }
            if (!"Created".equals(item.getStatus())) {
                continue;
            }
            JsonNode data = item.getData();
            if (requested.equals(data.path("actionTypeKey").asText())
                    && thirdParty == data.path("thirdParty").asBoolean(false)) {

View on GitHub (pinned to 62ff490619)

Solutions

  1. Set owner='Custom' when calling PollForJobs and owner='ThirdParty' when calling PollForThirdPartyJobs.
  2. Assert the owner value against the poll method name in worker startup code.
  3. Remember the corresponding action type must have been created with the same owner (CreateCustomActionType implies Custom).

Example fix

// before
client.poll_for_jobs(actionTypeId={
    'category': 'Build', 'owner': 'ThirdParty', 'provider': 'MyProvider', 'version': '1'})

// after
client.poll_for_jobs(actionTypeId={
    'category': 'Build', 'owner': 'Custom', 'provider': 'MyProvider', 'version': '1'})
Defensive patterns

Strategy: validation

Validate before calling

REQUIRED_OWNER = {'poll_for_jobs': 'Custom',
                 'poll_for_third_party_jobs': 'ThirdParty'}

def check_owner(method: str, action_type_id: dict) -> None:
    want = REQUIRED_OWNER[method]
    assert action_type_id.get('owner') == want, \
        f'{method} requires actionTypeId.owner == {want!r}'

check_owner('poll_for_jobs', action_type_id)
client.poll_for_jobs(actionTypeId=action_type_id)

Type guard

def owner_matches_poll(method: str, action_type_id: dict) -> bool:
    want = 'ThirdParty' if 'third_party' in method else 'Custom'
    return action_type_id.get('owner') == want

Try / catch

try:
    client.poll_for_third_party_jobs(actionTypeId=action_type_id)
except ClientError as e:
    if e.response['Error']['Code'] == 'ValidationException' and 'ThirdParty' in str(e):
        action_type_id = {**action_type_id, 'owner': 'ThirdParty'}
        client.poll_for_third_party_jobs(actionTypeId=action_type_id)
    else:
        raise

Prevention

When it happens

Trigger: Calling PollForJobs with actionTypeId={'owner': 'ThirdParty', ...} or PollForThirdPartyJobs with owner 'Custom'/'AWS'; copy-pasting a job-worker config between a custom-action worker and a third-party worker.

Common situations: Job workers configured from templates with the wrong owner string; swapping poll endpoints when migrating a provider from custom to third-party mode; owner left as the default 'AWS' from an SDK example struct.

Related errors


AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14). Data as JSON: /api/errors/82bbeb45a3b2737c. Report an issue: GitHub.