{"record":{"id":"259d73ab6c5d0e70","repo":"floci-io/floci","slug":"validationexception-259d73","errorCode":"ValidationException","errorMessage":"modelId is required.","messagePattern":"modelId is required\\.","errorType":"error_code","errorClass":"AwsException","httpStatus":400,"severity":"error","filePath":"src/main/java/io/github/hectorvent/floci/services/bedrockruntime/BedrockRuntimeController.java","lineNumber":49,"sourceCode":"public class BedrockRuntimeController {\n\n    private static final Logger LOG = Logger.getLogger(BedrockRuntimeController.class);\n\n    private final BedrockRuntimeService service;\n    private final ObjectMapper objectMapper;\n\n    @Inject\n    public BedrockRuntimeController(BedrockRuntimeService service, ObjectMapper objectMapper) {\n        this.service = service;\n        this.objectMapper = objectMapper;\n    }\n\n    @POST\n    @Blocking\n    @Path(\"/{modelId:.+}/converse\")\n    public Response converse(@PathParam(\"modelId\") String modelId, String body) {\n        if (modelId == null || modelId.isBlank()) {\n            throw new AwsException(\"ValidationException\", \"modelId is required.\", 400);\n        }\n        JsonNode request;\n        try {\n            request = body == null || body.isBlank()\n                    ? objectMapper.createObjectNode()\n                    : objectMapper.readTree(body);\n        } catch (Exception e) {\n            throw new AwsException(\"ValidationException\",\n                    \"Malformed request body: \" + e.getMessage(), 400);\n        }\n\n        JsonNode messages = request.path(\"messages\");\n        if (!messages.isArray() || messages.isEmpty()) {\n            throw new AwsException(\"ValidationException\",\n                    \"messages is required and must be a non-empty array.\", 400);\n        }\n\n        ObjectNode response = service.buildConverseResponse(modelId, (ObjectNode) request);","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/services/bedrockruntime/BedrockRuntimeController.java#L31-L67","documentation":"Thrown by Floci's Bedrock Runtime REST controller when the {modelId} path parameter on POST /{modelId}/converse is missing or blank. Because the JAX-RS path template requires {modelId:.+}, this is mostly defensive — it fires when the routed modelId resolves to an empty string.","triggerScenarios":"POSTing to /model/invoke or /converse with a URL that yields an empty modelId segment (e.g. trailing-slash or rewrite quirks), or calling Converse with a model id composed only of characters stripped by routing.","commonSituations":"Base-URL misconfiguration where the SDK endpoint path is rewritten; using a proxy or ALB rule that drops the model id segment; SDK configured with an endpoint override lacking the model in the path.","solutions":["Verify the request URL looks like POST https://host/model/<modelId>/converse with a non-empty modelId","Check the AWS SDK endpoint override and any reverse-proxy rewrite rules in front of Floci","Confirm the Bedrock client is constructed with a concrete model id (e.g. anthropic.claude-3-haiku-...) so the SDK builds the right path"],"exampleFix":"// before\nbedrockRuntimeClient.converse(req -> req.modelId(\"\"));\n// after\nbedrockRuntimeClient.converse(req -> req.modelId(\"anthropic.claude-3-haiku-20240307-v1:0\"));","handlingStrategy":"validation","validationCode":"if (modelId == null || modelId.isBlank()) throw new IllegalArgumentException(\"modelId required\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Centralize Bedrock client construction so modelId is always set from config","Smoke-test endpoint overrides with a single Converse call at startup"],"tags":["bedrock","validation","routing","floci"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}