alibaba/spring-ai-alibaba · error · RuntimeException

Failed to parse store key

Error message

Failed to parse store key: {storeKey}

What it means

parseStoreKey decodes a Base64 store key back into {namespace, key}; if decoding or JSON parsing fails it throws RuntimeException("Failed to parse store key: <key>"). A malformed, corrupted, or non-library-generated storeKey cannot be round-tripped, so the operation aborts with the offending key in the message.

Solutions

  1. Verify the storeKey is intact, valid Base64, and was produced by createStoreKey (decode it manually to check).
  2. Re-derive the key from namespace+key with createStoreKey instead of reusing cached/hand-copied values.
  3. Catch RuntimeException around parseStoreKey and treat invalid keys as not-found; log the full key for diagnosis.
  4. If keys came from an older library version, migrate/re-encode stored keys with the current createStoreKey.

Example fix

// before
Object[] nsKey = store.parseStoreKey(storedKey);
// after
try {
    Object[] nsKey = store.parseStoreKey(storedKey.trim());
} catch (RuntimeException e) {
    log.warn("Corrupt store key, rebuilding", e);
    String rebuilt = store.createStoreKey(expectedNamespace, expectedKey);
    Object[] nsKey = store.parseStoreKey(rebuilt);
}
Defensive patterns

Strategy: try-catch

Validate before calling

boolean looksLikeStoreKey(String k) {
    if (k == null || k.isBlank()) return false;
    try { java.util.Base64.getDecoder().decode(k); return true; }
    catch (IllegalArgumentException e) { return false; }
}

Type guard

boolean isValidStoreKey(String k) {
    if (k == null || k.isBlank()) return false;
    try { java.util.Base64.getDecoder().decode(k); return true; }
    catch (IllegalArgumentException e) { return false; }
}

Try / catch

try {
    Object[] nsKey = store.parseStoreKey(storeKey.trim());
} catch (RuntimeException e) {
    log.warn("Unparseable store key: {}", e.getMessage());
    throw new ResourceNotFoundException("store key invalid");
}

Prevention

When it happens

Trigger: Passing a storeKey that was truncated, hand-edited, generated by a different key scheme/version, or not valid Base64/JSON into APIs that accept a storeKey (e.g. reading by stored key reference).

Common situations: Migrating data between store implementations with different key formats; copying keys from logs with clipping/whitespace; upgrading the library after the key encoding changed; manually constructing keys.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/7942a575848eba97. Report an issue: GitHub.

Appendix: source

Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/store/stores/BaseStore.java:148

		}
	}

	/**
	 * Parse store key to namespace and key.
	 * @param storeKey store key
	 * @return array containing [namespace, key]
	 */
	@SuppressWarnings("unchecked")
	protected Object[] parseStoreKey(String storeKey) {
		try {
			byte[] decoded = Base64.getDecoder().decode(storeKey);
			Map<String, Object> keyData = new ObjectMapper().readValue(decoded, Map.class);
			List<String> namespace = (List<String>) keyData.get("namespace");
			String key = (String) keyData.get("key");
			return new Object[] { namespace, key };
		}
		catch (Exception e) {
			throw new RuntimeException("Failed to parse store key: " + storeKey, e);
		}
	}

	/**
	 * Check if namespace starts with given prefix.
	 * @param namespace namespace to check
	 * @param prefix prefix to match
	 * @return true if starts with prefix
	 */
	protected boolean startsWithPrefix(List<String> namespace, List<String> prefix) {
		if (prefix.isEmpty()) {
			return true;
		}
		if (prefix.size() > namespace.size()) {
			return false;
		}
		for (int i = 0; i < prefix.size(); i++) {
			if (!Objects.equals(namespace.get(i), prefix.get(i))) {

View on GitHub (pinned to f82da0b50f)