chinabugotech/hutool · error · IllegalArgumentException

attribute [{}] cannot mirror for [{}], because it's already

Error message

attribute [{}] cannot mirror for [{}], because it's already mirrored for [{}]

What it means

One of two near-identical messages from MirrorLinkAnnotationPostProcessor.checkMirrorRelation. This variant fires when an attribute is annotated @Link(type=MIRROR_FOR) pointing at another attribute, but that mirror relationship is inconsistent: specifically the branch where only one side has already been mirrored to a different target. It indicates a malformed mutual @Link/@MirrorFor setup that the processor cannot reconcile.

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/annotation/MirrorLinkAnnotationPostProcessor.java:111

		}
		// 镜像字段已经跟其他字段形成镜像
		else if (!originalAttributeMirrored && mirrorAttributeMirrored) {
			errorMsg = CharSequenceUtil.format(
				"attribute [{}] cannot mirror for [{}], because it's already mirrored for [{}]",
				mirror.getAttribute(), original.getAttribute(), ((MirroredAnnotationAttribute)mirror).getLinked()
			);
		}
		// 两者都形成了镜像,但是都未指向对方,理论上不会存在该情况
		else {
			errorMsg = CharSequenceUtil.format(
				"attribute [{}] cannot mirror for [{}], because [{}] already mirrored for [{}] and  [{}] already mirrored for [{}]",
				mirror.getAttribute(), original.getAttribute(),
				mirror.getAttribute(), ((MirroredAnnotationAttribute)mirror).getLinked(),
				original.getAttribute(), ((MirroredAnnotationAttribute)original).getLinked()
			);
		}

		throw new IllegalArgumentException(errorMsg);
	}

	/**
	 * 基本校验
	 */
	private void checkMirrorRelation(Link annotation, AnnotationAttribute original, AnnotationAttribute mirror) {
		// 镜像属性必须存在
		checkLinkedAttributeNotNull(original, mirror, annotation);
		// 镜像属性返回值必须一致
		checkAttributeType(original, mirror);
		// 镜像属性上必须存在对应的注解
		final Link mirrorAttributeAnnotation = getLinkAnnotation(mirror, RelationType.MIRROR_FOR);
		Assert.isTrue(
			ObjectUtil.isNotNull(mirrorAttributeAnnotation) && RelationType.MIRROR_FOR.equals(mirrorAttributeAnnotation.type()),
			"mirror attribute [{}] of original attribute [{}] must marked by @Link, and also @LinkType.type() must is [{}]",
			mirror.getAttribute(), original.getAttribute(), RelationType.MIRROR_FOR
		);
		checkLinkedSelf(original, mirror);

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Ensure MIRROR_FOR links are symmetric: if A mirrors B, B must mirror A.
  2. Remove stray @Link annotations left from refactoring.
  3. Inspect the error's listed attributes to find which side is double-linked and fix its @Link target.
Defensive patterns

Strategy: validation

Validate before calling

// verify mirror pairs are symmetric before relying on synthesis
boolean aMirrorsB = isMirrorFor(A.class, "a", B.class, "b");
boolean bMirrorsA = isMirrorFor(B.class, "b", A.class, "a");
if (aMirrorsB != bMirrorsA) throw new IllegalStateException("asymmetric mirror");

Prevention

When it happens

Trigger: Defining @Link(... MIRROR_FOR) on attribute A pointing to B, while B's @Link points elsewhere (or B has no reciprocal @Link), creating an asymmetric mirror graph. Mixing @Alias with @Link MIRROR_FOR on overlapping members.

Common situations: Building a custom composed-annotation hierarchy where mirrored members are not declared pairwise; refactoring one half of a mirror pair and forgetting the other; version upgrade that changed mirror semantics.

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/dc26cf0b9eaebe0e. Report an issue: GitHub.