{"record":{"id":"f7cde2477f129f49","repo":"floci-io/floci","slug":"override-s-must-not-contain-whitespace","errorCode":null,"errorMessage":"Override %s must not contain whitespace.","messagePattern":"Override (.+?) must not contain whitespace\\.","errorType":"http","errorClass":"AwsException","httpStatus":400,"severity":"warning","filePath":"src/main/java/io/github/hectorvent/floci/core/common/ReservedTags.java","lineNumber":173,"sourceCode":"        }\n        return normalized;\n    }\n\n    private static String validateClientSecret(String overrideSecret, String name, String errorCode) {\n        String normalized = checkNullAndWhitespace(overrideSecret, name, errorCode);\n        if (normalized.chars().anyMatch(Character::isISOControl)) {\n            throw new AwsException(errorCode, CONTROL_CHARACTER_ERROR_MESSAGE.formatted(name), 400);\n        }\n        return normalized;\n    }\n\n    private static String checkNullAndWhitespace(String overrideSecret, String name, String errorCode) {\n        if (overrideSecret == null || overrideSecret.trim().isEmpty()) {\n            throw new AwsException(errorCode, \"Override %s must not be blank.\".formatted(name), 400);\n        }\n        String normalized = overrideSecret.trim();\n        if (normalized.chars().anyMatch(Character::isWhitespace)) {\n            throw new AwsException(errorCode, \"Override %s must not contain whitespace.\".formatted(name), 400);\n        }\n        return normalized;\n    }\n\n\n    private static boolean isReserved(String key) {\n        return key != null && key.startsWith(RESERVED_PREFIX);\n    }\n}\n","sourceCodeStart":155,"sourceCodeEnd":183,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/core/common/ReservedTags.java#L155-L183","documentation":"Thrown by the manual-approval wait loop when the approval action ends in the 'Failed' status; the exception message is the action's summary, which for approvals is typically set by RetryStageExecution/approval rejection or by whatever transition set status to Failed. The emulator blocks the execution thread, polling until the action leaves InProgress, then converts a Failed terminal state into ActionExecutionFailed.","triggerScenarios":"An approval action rejected via the approval flow (the emulator sets the stage action to Failed with a rejection summary); approval marked failed programmatically; an external update to the action's status to Failed while waiting.","commonSituations":"A human or automation rejecting a deployment gate in tests; pipelines left waiting on approval that a cleanup script then fails; stop/abandon paths that record a failure summary.","solutions":["Treat this as the expected terminal outcome of a rejected approval — inspect the action's summary in GetPipelineState/execution details for who/why","If the rejection is unexpected, re-run the pipeline execution and approve via the recorded approval token","For automated emulator tests, either approve the token or assert the ActionExecutionFailed as the rejection signal"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    client.startPipelineExecution(r -> r.name(name));\n} catch (ActionExecutionFailedException e) {\n    if (\"Waiting for approval.\".contains(e.getMessage()) || e.getMessage().contains(\"approval\")) {\n        // expected rejection path; assert summary instead of failing the test\n    }\n}","preventionTips":["In automation, resolve approval tokens programmatically or exclude approval stages from emulator test pipelines","Set distinct summaries when rejecting approvals so failures are attributable"],"tags":["codepipeline","manual-approval","action-failed","approval"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}