floci-io/floci · error · AwsException

CustomResourceTimeout

CustomResourceTimeout

Error message

Timed out waiting for custom resource {} to PUT its response to ResponseURL

What it means

The custom resource Lambda invoke succeeded (no FunctionError), but the handler never PUT its response to the ResponseURL within CR_RESPONSE_TIMEOUT — customResourceResponseStore.await(token, ...) timed out. Floci surfaces this as CustomResourceTimeout with HTTP 504. Under the synchronous Pattern 1 design the response is expected immediately after the handler returns.

Source

Thrown at src/main/java/io/github/hectorvent/floci/services/cloudformation/CloudFormationResourceProvisioner.java:5066

            if (oldResourceProperties != null) {
                event.set("OldResourceProperties", oldResourceProperties);
            }

            byte[] payload = objectMapper.writeValueAsBytes(event);
            InvokeResult result = lambdaService.invoke(region, serviceToken, payload,
                    InvocationType.RequestResponse);
            if (result.getFunctionError() != null) {
                String body = result.getPayload() != null
                        ? new String(result.getPayload(), StandardCharsets.UTF_8) : "";
                throw new AwsException("CustomResourceFailed",
                        "Custom resource handler errored (" + result.getFunctionError() + "): " + body, 400);
            }

            return customResourceResponseStore.await(token, CR_RESPONSE_TIMEOUT);
        } catch (AwsException e) {
            throw e;
        } catch (TimeoutException e) {
            throw new AwsException("CustomResourceTimeout",
                    "Timed out waiting for custom resource " + logicalId
                            + " to PUT its response to ResponseURL", 504);
        } catch (Exception e) {
            throw new AwsException("CustomResourceFailed",
                    "Failed to invoke custom resource " + logicalId + ": " + e.getMessage(), 500);
        }
    }

    private static String nodeToAttributeValue(JsonNode node) {
        if (node == null || node.isNull()) {
            return "";
        }
        return node.isValueNode() ? node.asText() : node.toString();
    }

    /**
     * Mirrors CloudFormation's stringification of custom-resource ResourceProperties: every scalar
     * (boolean, number, text) becomes a string, while object and array structure is preserved.

View on GitHub (pinned to 62ff490619)

Solutions

  1. Make sure the handler PUTs to event['ResponseURL'] before it returns — in Node await the PUT, in Python call cfnresponse.send synchronously.
  2. Add/verify logging around the response PUT and check the Floci CfnResponseController received anything at all.
  3. Shorten or split the handler's work so it finishes within the configured timeout, or emit SUCCESS early only when work is truly done.
  4. Confirm the handler is Pattern 1 (single synchronous Lambda); async provider-framework handlers need rewriting or a synchronous wrapper.

Example fix

// before (Node): PUT fires after return, races the waiter
export const handler = async (event) => { doWork(event); sendResponse(event); }
// after
export const handler = async (event) => {
  await doWork(event);
  await sendResponse(event); // PUT completes before handler returns
}
Defensive patterns

Strategy: retry

Try / catch

try {
    stackOps.executeChangeSet(name, cs);
} catch (AwsException e) {
    if ("CustomResourceTimeout".equals(e.getCode())) {
        // transient: handler may have PUT just after the window — safe to re-run the change set
        return retryWithBackoff();
    }
    throw e;
}

Prevention

When it happens

Trigger: Handler returns 200 without calling cfnresponse.send / without PUTting to the ResponseURL; handler PUTs asynchronously after returning (deferred thread/callback) so the PUT races past the wait; handler took longer than the timeout before responding.

Common situations: Node handlers that respond via a callback after the main function returns without awaiting it; handlers written for the async Provider framework that skip the response PUT; long-running work exceeding CR_RESPONSE_TIMEOUT; response PUT sent to a wrong/rotated URL.

Understand the failure class

Related errors


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