ErrLookup › Background articles › "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires
"is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires
Errors like "source is not a compatible type", "failed to merge statements", and "instance is not a RGB image" all fire when a library checks a value's concrete type up front and refuses to proceed. These incompatible-source-type errors surface at config load, evaluation, scan, or deserialization time. Here is why they exist and how to fix them.
Distilled from 526 documented records across 65 repositories.
Background
This family covers a defensive pattern: a library accepts a value or reference, verifies its concrete type against what the operation actually needs, and fails fast with an explicit error instead of misbehaving later. In googleapis/mcp-toolbox, ValidateSource performs a type assertion against a private compatibleSource interface when a tool's source field in tools.yaml points at the wrong engine, catching the mistake at config load time. In deeplearning4j, OutputLayerUtil rejects classifier evaluation classes when the network's output layer is a Yolo2OutputLayer, because classifier metrics are meaningless for object detection. In tomnomnom/gron, the ungron path fails when recursive merge finds the same key path assigned incompatible container types (object vs array).
The checks appear at many layers. Some are config-time: mcp-toolbox validates the tools file at startup, and shadcn-ui's cn migration asserts declared tailwindcss and tailwind-merge versions in package.json before rewriting anything. Some are runtime validation: Yalantis/uCrop throws CImgInstanceException when RGBtoHSI is called on an image whose channel count is not 3, and cocoindex refuses to declare a vector index on a PostgreSQL column that is not a vector or halfvec type. Some sit at the data boundary: coder's sqlc-generated Scan methods only accept []byte or string for enum columns and return "unsupported scan type" for anything else a driver delivers, while microg's DataBundle reader rejects lists whose elements have mixed types during deserialization.
A notable sub-family guards filesystem invariants against concurrent modification. astrid-runtime aborts migration inventory when a file swapped to a symlink or fifo between the directory scan and the open (a TOCTOU guard), libnyanpasu refuses journal phase transitions when the destination path holds a symlink or non-regular file, and kopia's resolveSymlink gives up when a symlink chain lands on a directory or special file because ignore rules can only match file entries. owasp-amass is the outlier: its "%s is not compressed" detection error is informational by design and GetListFromFile deliberately swallows it, reading the file as plain text.
The failure is almost always treated as fatal, but the behaviour is library-specific: most of these checks abort the operation outright, while owasp-amass deliberately treats the mismatch as informational and continues. Exception classes vary by language — IllegalStateException and IllegalArgumentException dominate on the JVM — but the shape is identical: an up-front type check whose message usually names both what was found and what was required.
Common causes
- Wrong source or component wired to a consumer. A config field references an entity of the wrong kind, such as an mcp-toolbox tool pointing at a non-Spark source, so the type assertion fails at load time. Fix the reference so kinds match.
- API used on an incompatible object type. Calling an operation with a value whose concrete type it does not support, like classifier evaluation on a Yolo2OutputLayer network or RGBtoHSI on a non-3-channel image. Use the type-specific API instead.
- Mixed or conflicting shapes in aggregate input. Input items that must be homogeneous are not: gron statements assigning both an object and an array to the same key, or microG DataBundle lists containing elements of different types. Make every element at a path share one type.
- Version or serializer mismatch on stored data. Data written by one implementation is read by another that expects a different type or contract, as in spring-ai-alibaba checkpoint rows written with a different serializer's content type, mise remote cache metadata with an unsupported version, or PageHelper reflecting on a mybatis jar lacking an expected field.
- Files swapped or replaced by non-regular entries. Concurrent modification or sync tools replace expected regular files with symlinks, directories, or fifos, tripping TOCTOU guards in astrid, clash-nyanpasu journals, and kopia symlink resolution. Quiesce the tree and exclude state directories from sync tools.
- Driver or wire format delivering unexpected types. An underlying layer hands over a representation the consumer does not accept, such as a database driver scanning a NULL or integer into coder's UserStatus enum. Use nullable generated types, COALESCE in SQL, or a supported driver.
- Annotation or class not satisfying a required contract. A reflectively loaded or processor-visited element does not implement the expected interface, as in PermissionsDispatcher's WrongClassException or LanguageTool filter classes lacking RuleFilter. Move the annotation or add the missing interface.
What usually fixes it
- Check the concrete type before the call: inspect what the error names as found versus required, and either convert the value to the expected type or switch to the API variant meant for that type.
- Align configuration references so kinds match: pair each tool, index, or evaluation with a source, column, or layer of the compatible kind, and re-run the load or startup validation to catch mistakes early.
- Make inputs homogeneous: ensure every element at a shared path or in a list uses one container or element type, and validate pre-merged or pre-deserialized input before handing it to the library.
- Keep writer and reader contracts in lockstep: match versions across clients, pin serializer configuration, and migrate or purge stored data when the format or version changes.
- Quiesce the filesystem before type-checked operations: stop sync and backup tools, exclude private state and journal directories, and retry after removing any symlink or non-file artifact left by a crash.
Go deeper
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Documented occurrences
- failed to merge statements (tomnomnom/gron)
- invalid source for %q tool: source %q is not a compatible type (googleapis/mcp-toolbox)
- Classifier evaluation using ${classifierEval.getSimpleName()} class cannot be applied for object detection evaluation using Yolo2OutputLayer: ${classifierEval.getSimpleName()} class is for classifier evaluation only. (deeplearning4j/deeplearning4j)
- '${TypeName.get(type)}' can't be annotated with '@RuntimePermissions' (permissions-dispatcher/PermissionsDispatcher)
- AggregatorFactoryNotMergeableException (apache/druid)
- %s is not compressed (owasp-amass/amass)
- %s is not %s media (detected mime: %s) (chenhg5/cc-connect)
- layout migration source changed type: {} (astrid-runtime/astrid)
- journal destination is not a regular file: {} (libnyanpasu/clash-nyanpasu)
- Content Type used for store state '%s' is different from one '%s' used for deserialize it (alibaba/spring-ai-alibaba)
- unsupported remote cache client metadata version (jdx/mise)
- Cannot coerce '{0}' of {1} to {2} (incompatible type) (Activiti/Activiti)
- Unsupported input type for CEL evaluation: ${input class name or null} (grpc/grpc-java)
- Invalid AgentClass: (pinpoint-apm/pinpoint)
- Filter class '${className}' must implement interface ${RuleFilter.class.getSimpleName()} (languagetool-org/languagetool)
- RGBtoHSI(): Instance is not a RGB image. (Yalantis/uCrop)
- The database must be manually upgraded. Please backup the database and browse /setup. For more information: %s (SonarSource/sonarqube)
- Failed to convert InstrumentAny to Python: {e} (nautechsystems/nautilus_trader)
- %s does not eventually link to a file (kopia/kopia)
- event has multiple source types : %s != %s (crowdsecurity/crowdsec)
…and 506 more across the corpus — use search.
Honest provenance: generated on 2026-09-09 from AI-assisted analysis of the linked records. See how records are made.