spring-projects/spring-ai · error · IllegalArgumentException

Field ' ' is not a TEXT field

Error message

Field '%s' is not a TEXT field

What it means

RedisVectorStore.validateTextField() (used by text-based search, e.g. searchByText) verifies that the requested field is declared with FieldType.TEXT in the index metadata. If the normalized field name is not a TEXT field, it throws this IllegalArgumentException after logging the available TEXT fields in debug mode. Searching with full-text match operators on TAG or NUMERIC fields is not allowed.

Solutions

  1. Declare the field with FieldType.TEXT in the store's metadataFields configuration
  2. Pass the field name exactly as declared (without '@' or JSON path prefix)
  3. Enable debug logging to see the available TEXT fields and pick a valid one
  4. If the field should be tag-searchable, use the corresponding tag filter API instead of text search

Example fix

// before
RedisVectorStore.builder().metadataFields(new MetadataField("description", FieldType.TAG)) ... searchByText("description", q)
// after
RedisVectorStore.builder().metadataFields(new MetadataField("description", FieldType.TEXT)) ... searchByText("description", q)
Defensive patterns

Strategy: validation

Validate before calling

boolean isText = storeFields.stream().anyMatch(f -> f.name().equals(fieldName) && f.fieldType() == FieldType.TEXT);
if (!isText) throw new IllegalArgumentException(fieldName + " is not a TEXT field");

Type guard

static boolean isTextField(MetadataField f) { return f != null && f.fieldType() == FieldType.TEXT; }

Try / catch

try { store.searchByText(field, query); } catch (IllegalArgumentException e) { if (e.getMessage().contains("is not a TEXT field")) { /* use a declared TEXT field or tag-search API */ } }

Prevention

When it happens

Trigger: Calling a text search API with a field name that is either not indexed at all, indexed as TAG or NUMERIC, or that normalizes (prefix/@path stripping) to a different name than the declared one.

Common situations: Using a tag field (exact-match) in a full-text search call; field name passed with '@' or JSON-path prefix that does not match after normalization; typo in the field name; store configured with metadataFields that omit TEXT declarations for the field.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at vector-stores/spring-ai-redis-store/src/main/java/org/springframework/ai/vectorstore/redis/RedisVectorStore.java:789

		if (normalizedFieldName.equals(this.contentFieldName)) {
			return;
		}

		// Check if it's a metadata field with TEXT type
		boolean isTextField = this.metadataFields.stream()
			.anyMatch(field -> field.name().equals(normalizedFieldName) && field.fieldType() == FieldType.TEXT);

		if (!isTextField) {
			// Log detailed metadata fields for debugging
			if (logger.isDebugEnabled()) {
				logger.debug("Field not found as TEXT: '" + normalizedFieldName + "'");
				logger.debug("Content field name: '" + this.contentFieldName + "'");
				logger.debug("Available TEXT fields: " + this.metadataFields.stream()
					.filter(field -> field.fieldType() == FieldType.TEXT)
					.map(MetadataField::name)
					.toList());
			}
			throw new IllegalArgumentException(String.format("Field '%s' is not a TEXT field", normalizedFieldName));
		}
	}

	/**
	 * Normalizes a field name by removing @ prefix and JSON path prefix.
	 * @param fieldName the field name to normalize
	 * @return the normalized field name
	 */
	private String normalizeFieldName(String fieldName) {
		String result = fieldName;
		if (result.startsWith("@")) {
			result = result.substring(1);
		}
		if (result.startsWith(JSON_PATH_PREFIX)) {
			result = result.substring(JSON_PATH_PREFIX.length());
		}
		return result;
	}

View on GitHub (pinned to 98a7beda4f)