spring-projects/spring-ai · warning

Failed to ensure Neo4j indexes for chat memory: +…

Error message

Failed to ensure Neo4j indexes for chat memory: + e.getMessage()

What it means

This is a warning logged by Neo4jChatMemoryRepositoryConfig.ensureIndexes() when it fails to create the conversationId and messageId indexes used for chat memory lookups. It wraps any Exception thrown while executing the index Cypher statements; the library deliberately swallows the exception (warn only) so application startup is not blocked, but indexes may be missing and queries will scan.

Solutions

  1. Verify Neo4j connectivity and credentials (spring.neo4j.uri, authentication username/password) and confirm the database is up before app start
  2. Check the full stack trace / underlying Neo4j exception; this log only carries e.getMessage()
  3. Grant the connected role schema/index privileges (e.g. GRANT CREATE INDEX ON DBMS) or use an admin user
  4. Create the indexes manually with CREATE INDEX ... IF NOT EXISTS so ensureIndexes becomes a no-op
  5. Retry after fixing; the check runs on repository initialization

Example fix

// before
Neo4jChatMemoryRepositoryConfig.builder().build(); // fails silently if Neo4j down
// after
// ensure Neo4j is reachable first
try (Driver driver = GraphDatabase.driver(uri, AuthTokens.basic(user, pass))) {
    driver.verifyConnectivity();
}
Neo4jChatMemoryRepositoryConfig.builder().build();
Defensive patterns

Strategy: try-catch

Validate before calling

try (Driver d = GraphDatabase.driver(neo4jUri, AuthTokens.basic(user, pass))) { d.verifyConnectivity(); } // also verify role: SHOW CURRENT USER PRIVILEGES includes 'CREATE INDEX'

Type guard

boolean neo4jReady = driver != null && session != null && session.isOpen();

Try / catch

// the library already catches; guard at startup:
try { repository = Neo4jChatMemoryRepositoryConfig.builder().build(); }
catch (Exception e) { throw new IllegalStateException("Neo4j chat memory index setup failed; check connectivity/privileges", e); }

Prevention

When it happens

Trigger: Any exception from session.run(sessionIndexCypher) or session.run(messageIndexCypher) during repository init: Neo4j is unreachable, credentials wrong, the database is down/renamed, or the connected user lacks index-creation privileges.

Common situations: Dev environments where Neo4j isn't started yet or Docker container not up; wrong spring.neo4j.uri/password; connecting to an Aura or clustered instance with a restricted role lacking schema privileges; database name configured other than neo4j.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/3b54b053bd43021c. Report an issue: GitHub.

Appendix: source

Thrown at memory-repositories/spring-ai-model-chat-memory-repository-neo4j/src/main/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4jChatMemoryRepositoryConfig.java:138

	 * Ensures that indexes exist on conversationId for Session nodes and index for
	 * Message nodes. This improves query performance for lookups and ordering.
	 */
	private void ensureIndexes() {
		try (var session = this.driver.session()) {
			// Index for conversationId on Session nodes
			String sessionIndexCypher = String.format(
					"CREATE INDEX session_conversation_id_index IF NOT EXISTS FOR (n:%s) ON (n.conversationId)",
					this.sessionLabel);
			// Index for index on Message nodes
			String messageIndexCypher = String
				.format("CREATE INDEX message_index_index IF NOT EXISTS FOR (n:%s) ON (n.index)", this.messageLabel);
			session.run(sessionIndexCypher);
			session.run(messageIndexCypher);
			logger.info("Ensured Neo4j indexes for conversationId and message index.");
		}
		catch (Exception e) {
			if (logger.isWarnEnabled()) {
				logger.warn("Failed to ensure Neo4j indexes for chat memory: " + e.getMessage());
			}
		}
	}

	public static Builder builder() {
		return new Builder();
	}

	public static final class Builder {

		private @Nullable Driver driver;

		private String sessionLabel = DEFAULT_SESSION_LABEL;

		private String toolCallLabel = DEFAULT_TOOL_CALL_LABEL;

		private String metadataLabel = DEFAULT_METADATA_LABEL;

View on GitHub (pinned to 98a7beda4f)