{"record":{"id":"8c3360177a079a63","repo":"elastic/elasticsearch","slug":"database-s-is-already-being-downloaded-via-conf","errorCode":null,"errorMessage":"database [%s] is already being downloaded via configuration [%s]","messagePattern":"database \\[(.+?)\\] is already being downloaded via configuration \\[(.+?)\\]","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/ip-location/src/main/java/org/elasticsearch/ingest/geoip/direct/TransportPutDatabaseConfigurationAction.java","lineNumber":127,"sourceCode":"            return newDatabase.equals(existingDatabase.database());\n        }\n    }\n\n    static void validatePrerequisites(ProjectId projectId, DatabaseConfiguration database, ClusterState state) {\n        // we need to verify that the database represents a unique file (name) among the various databases for this same provider\n        IngestGeoIpMetadata geoIpMeta = state.metadata().getProject(projectId).custom(IngestGeoIpMetadata.TYPE, IngestGeoIpMetadata.EMPTY);\n\n        Optional<DatabaseConfiguration> sameName = geoIpMeta.getDatabases()\n            .values()\n            .stream()\n            .map(DatabaseConfigurationMetadata::database)\n            // .filter(d -> d.type().equals(database.type())) // of the same type (right now the type is always just 'maxmind')\n            .filter(d -> d.id().equals(database.id()) == false) // and a different id\n            .filter(d -> d.name().equals(database.name())) // but has the same name!\n            .findFirst();\n\n        sameName.ifPresent(d -> {\n            throw new IllegalArgumentException(\n                Strings.format(\"database [%s] is already being downloaded via configuration [%s]\", database.name(), d.id())\n            );\n        });\n    }\n\n    private record UpdateDatabaseConfigurationTask(\n        ProjectId projectId,\n        ActionListener<AcknowledgedResponse> listener,\n        DatabaseConfiguration database\n    ) implements ClusterStateTaskListener {\n\n        ClusterState execute(ClusterState currentState) throws Exception {\n            final var project = currentState.metadata().getProject(projectId);\n            IngestGeoIpMetadata geoIpMeta = project.custom(IngestGeoIpMetadata.TYPE, IngestGeoIpMetadata.EMPTY);\n\n            String id = database.id();\n            final DatabaseConfigurationMetadata existingDatabase = geoIpMeta.getDatabases().get(id);\n            // double-check for no-op in the state update task, in case it was changed/reset in the meantime","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/ip-location/src/main/java/org/elasticsearch/ingest/geoip/direct/TransportPutDatabaseConfigurationAction.java#L109-L145","documentation":"Thrown by TransportPutDatabaseConfigurationAction.validatePrerequisites when another database configuration with a DIFFERENT id but the SAME name already exists. The 'name' (e.g. 'GeoLite2-City') maps to a single underlying database file per provider; two configs downloading the same file would duplicate work and waste bandwidth, so the second PUT is rejected.","triggerScenarios":"PUT _ingest/geoip/database/<new-id> with a body whose 'name' equals the 'name' of an existing configuration that has a different id. For example, config 'city-a' has name 'GeoLite2-City'; PUT 'city-b' with name 'GeoLite2-City' fails.","commonSituations":"Renaming a config by creating a new id with the same name instead of updating the old one; duplicating a config to change account_id without changing the name; re-creating after a failed delete left the original in place.","solutions":["Reuse the existing configuration id: PUT _ingest/geoip/database/<existing-id> to update it in place.","DELETE the old configuration first, then PUT the new id with the same name.","Give the new configuration a different 'name' if you genuinely want two separate database files."],"exampleFix":"// before: 'city-a' already exists with name 'GeoLite2-City'\nPUT _ingest/geoip/database/city-b\n{ \"name\": \"GeoLite2-City\", \"maxmind\": { \"account_id\": \"999\" } }\n\n// after: update the existing id instead\nPUT _ingest/geoip/database/city-a\n{ \"name\": \"GeoLite2-City\", \"maxmind\": { \"account_id\": \"999\" } }","handlingStrategy":"validation","validationCode":"// Before PUT, ensure the name is not already used by another id\nMap<String, DatabaseConfiguration> existing = client.geoipDatabases().all();\nString newName = body.get(\"name\");\nboolean nameTaken = existing.entrySet().stream()\n    .anyMatch(e -> !e.getKey().equals(myId) && newName.equals(e.getValue().name()));\nif (nameTaken) {\n    throw new IllegalStateException(\"name '\" + newName + \"' already used by another config id\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reuse the existing id to update a config rather than creating a new one with the same name.","DELETE the old config before PUTting a new id that reuses the name.","Treat 'name' as a unique file identifier per provider, not just a label."],"tags":["elasticsearch","geoip","validation","duplicate","configuration","rest-api"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}