{"record":{"id":"795985a56de4029b","repo":"floci-io/floci","slug":"apikeylimitexceededexception","errorCode":"ApiKeyLimitExceededException","errorMessage":"The API key exceeded a limit.","messagePattern":"The API key exceeded a limit\\.","errorType":"exception","errorClass":"AwsException","httpStatus":400,"severity":"error","filePath":"src/main/java/io/github/hectorvent/floci/services/appsync/AppSyncService.java","lineNumber":576,"sourceCode":"        if (request.containsKey(\"description\")) existing.setDescription((String) request.get(\"description\"));\n        if (request.containsKey(\"format\")) existing.setFormat(parseEnum(TypeFormat.class, request.get(\"format\")));\n        typeStore.put(apiKey(apiId, typeName), existing);\n        return existing;\n    }\n\n    public void deleteType(String apiId, String typeName) {\n        assertSchemaNotBusy(apiId);\n        getType(apiId, typeName);\n        typeStore.delete(apiKey(apiId, typeName));\n    }\n\n    // ──────────────────────────── API Keys ────────────────────────────\n\n    public ApiKey createApiKey(String apiId, Map<String, Object> request) {\n        getGraphqlApi(apiId);\n        long existingCount = apiKeyStore.scan(k -> k.startsWith(apiId + \"::\")).size();\n        if (existingCount >= 2) {\n            throw new AwsException(\"ApiKeyLimitExceededException\",\n                    \"The API key exceeded a limit.\", 400);\n        }\n        ApiKey key = new ApiKey();\n        key.setId(generateShortId());\n        key.setApiId(apiId);\n        key.setDescription((String) request.get(\"description\"));\n        Object expiresValue = request.get(\"expires\");\n        if (expiresValue instanceof Long l) {\n            key.setExpires(l);\n        } else if (expiresValue instanceof Number n) {\n            key.setExpires(n.longValue());\n        } else if (expiresValue instanceof String s) {\n            try {\n                key.setExpires(Long.parseLong(s));\n            } catch (NumberFormatException e) {\n                try {\n                    key.setExpires(java.time.Instant.parse(s).getEpochSecond());\n                } catch (java.time.format.DateTimeParseException ex) {","sourceCodeStart":558,"sourceCodeEnd":594,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/services/appsync/AppSyncService.java#L558-L594","documentation":"Thrown by createApiKey when the API already has 2 or more API keys (counted via apiKeyStore scan of keys prefixed apiId + '::'). This emulates AWS AppSync's per-API API-key quota (ApiKeyLimitExceededException).","triggerScenarios":"Calling createApiKey on an apiId that already has two stored keys; e.g. creating a third key for rotation without deleting an old one.","commonSituations":"Key rotation scripts that create-then-delete instead of delete-then-create; tests that create fresh keys per iteration against the same API; long-lived emulator state accumulating keys across runs.","solutions":["Delete an existing API key first (deleteApiKey) so the count drops below the limit","Reuse an existing key via updateApiKey (e.g. extend 'expires') instead of creating a new one","If keys leaked from old tests, list and clean them up with listApiKeys + deleteApiKey"],"exampleFix":"// before\nappSync.createApiKey(apiId, Map.of(\"description\", \"rotated\")); // 3rd key -> limit\n\n// after\nvar keys = appSync.listApiKeys(apiId, null, null).getItems();\nappSync.deleteApiKey(apiId, keys.get(0).getId()); // drop oldest\nappSync.createApiKey(apiId, Map.of(\"description\", \"rotated\"));","handlingStrategy":"validation","validationCode":"var keys = appSync.listApiKeys(apiId, null, null).getItems();\nif (keys.size() >= 2) {\n    appSync.deleteApiKey(apiId, keys.get(0).getId()); // drop oldest\n}\nappSync.createApiKey(apiId, request);","typeGuard":null,"tryCatchPattern":"try {\n    appSync.createApiKey(apiId, request);\n} catch (AwsException e) {\n    if (\"ApiKeyLimitExceededException\".equals(e.getCode())) {\n        appSync.deleteApiKey(apiId, oldestKeyId);\n        appSync.createApiKey(apiId, request);\n    } else throw e;\n}","preventionTips":["Delete-then-create when rotating API keys, never create-then-delete","Track created key ids in tests and clean them up in teardown"],"tags":["appsync","api-key","quota","limits","aws"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}