{"record":{"id":"998ea94850c174f3","repo":"alibaba/spring-ai-alibaba","slug":"checkpoints-numretained-must-be-a-number-or-numeri","errorCode":null,"errorMessage":"checkpoints.numRetained must be a number or numeric string, got: <value class name>","messagePattern":"checkpoints\\.numRetained must be a number or numeric string, got: <value class name>","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/BaseCheckpointSaver.java","lineNumber":43,"sourceCode":"import static java.util.Optional.ofNullable;\n\npublic interface BaseCheckpointSaver {\n\tString THREAD_ID_DEFAULT = \"$default\";\n\tString CHECKPOINTS_NUM_RETAINED = \"checkpoints.numRetained\";\n\n\tdefault Optional<Checkpoint> getLast(LinkedList<Checkpoint> checkpoints, RunnableConfig config) {\n\t\treturn (checkpoints.isEmpty()) ? Optional.empty() : ofNullable(checkpoints.peek());\n\t}\n\n\tdefault Optional<Integer> checkpointsNumRetained(RunnableConfig config) {\n\t\treturn config.metadata(CHECKPOINTS_NUM_RETAINED).map(value -> {\n\t\t\tif (value instanceof Number number) {\n\t\t\t\treturn number.intValue();\n\t\t\t}\n\t\t\tif (value instanceof String text) {\n\t\t\t\treturn Integer.parseInt(text);\n\t\t\t}\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"checkpoints.numRetained must be a number or numeric string, got: \" + value.getClass().getName());\n\t\t}).filter(value -> value > 0);\n\t}\n\n\tdefault void retainLatestCheckpoints(LinkedList<Checkpoint> checkpoints, RunnableConfig config) {\n\t\tcheckpointsNumRetained(config).ifPresent(numRetained -> {\n\t\t\twhile (checkpoints.size() > numRetained) {\n\t\t\t\tcheckpoints.removeLast();\n\t\t\t}\n\t\t});\n\t}\n\n\tCollection<Checkpoint> list(RunnableConfig config);\n\n\tOptional<Checkpoint> get(RunnableConfig config);\n\n\tRunnableConfig put(RunnableConfig config, Checkpoint checkpoint) throws Exception;\n","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/BaseCheckpointSaver.java#L25-L61","documentation":"BaseCheckpointSaver.checkpointsNumRetained reads the checkpoints.numRetained value from RunnableConfig metadata. The value must be a Number or a numeric String; anything else (Boolean, Map, List, null object of other type) throws IllegalArgumentException naming the offending value's class.","triggerScenarios":"Passing a RunnableConfig whose metadata key checkpoints.numRetained is set to a non-numeric type, e.g. a Boolean, JSONObject, or nested Map.","commonSituations":"Loading config from JSON/YAML where the value is parsed as a non-numeric node (e.g. quoted incorrectly or wrapped in an object), or programmatically putting the wrong type into config metadata.","solutions":["Set checkpoints.numRetained to an int/Integer in RunnableConfig metadata","If loaded from JSON/YAML, ensure the value is an unquoted number and unwrap container nodes","Parse/coerce the value yourself before putting it into the config","Wrap retainLatestCheckpoints calls in try-catch and fall back to a default retention count"],"exampleFix":"// before\nconfig.meta(\"checkpoints.numRetained\", \"true\");\n// after\nconfig.meta(\"checkpoints.numRetained\", 10);","handlingStrategy":"validation","validationCode":"Object v = config.metadata().get(\"checkpoints.numRetained\");\nif (!(v instanceof Number) && !(v instanceof String s && s.matches(\"\\\\d+\"))) throw new IllegalArgumentException(\"bad checkpoints.numRetained: \" + v);","typeGuard":"Integer asInt(Object v) { if (v instanceof Number n) return n.intValue(); if (v instanceof String s) { try { return Integer.parseInt(s); } catch (NumberFormatException e) { return null; } } return null; }","tryCatchPattern":"try { saver.retainLatestCheckpoints(checkpoints, config); } catch (IllegalArgumentException e) { /* use default retention */ }","preventionTips":["Store numRetained as an Integer in metadata","Validate external config before feeding it into RunnableConfig","Unit-test config loading paths"],"tags":["checkpoint","config","type-mismatch"],"backgroundTag":"config-type-mismatch","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}