moeru-ai/airi · warning

[AIRI] Failed to patch built-in MToon outline shader: outlin

Error message

[AIRI] Failed to patch built-in MToon outline shader: outlineNormal is missing on geometry.

What it means

The outline material patch requires a custom outlineNormal geometry attribute (AIRI_OUTLINE_NORMAL_ATTRIBUTE_NAME) that an earlier pipeline stage is supposed to have computed. In the onMaterial hook, if the target mesh's geometry lacks that attribute, the patch is skipped with this warn naming the mesh — the built-in outline keeps its normal-based (potentially lower quality) behavior for that mesh only.

Source

Thrown at packages/stage-ui-three/src/composables/vrm/outline.ts:510

  return {
    onDispose({ vrm }) {
      disposeVrmOutlineRuntime(vrm)
    },
    onLoad({ vrm }) {
      prepareVrmOutlineRuntime(vrm)
    },
    onMaterial(context) {
      const { material } = context

      if (!isMToonMaterial(material) || material.isOutline === true)
        return

      const meshTarget = findVrmOutlineMeshTarget(context)
      if (!meshTarget)
        return

      if (!meshTarget.geometry.getAttribute(AIRI_OUTLINE_NORMAL_ATTRIBUTE_NAME)) {
        console.warn(
          '[AIRI] Failed to patch built-in MToon outline shader: outlineNormal is missing on geometry.',
          meshTarget.mesh.name,
        )
        return
      }

      patchBuiltInOutlineMaterial(meshTarget.builtInOutlineMaterial)
    },
  }
}

View on GitHub (pinned to 677329427f)

Solutions

  1. Verify the mesh went through the geometry pass that adds the attribute (register it the same way as working meshes).
  2. Ensure the geometry has valid normals before the pass runs (geometry.computeVertexNormals() if needed).
  3. Treat single-mesh warns as cosmetic; if all meshes warn, the pipeline ordering is broken — fix registration order.

Example fix

// before
mesh.geometry.setAttribute('outlineNormal', attr) // skipped for late-added meshes

// after
// recompute when geometry is (re)assigned
function ensureOutlineNormal(mesh: SkinnedMesh) {
  if (!mesh.geometry.getAttribute(AIRI_OUTLINE_NORMAL_ATTRIBUTE_NAME))
    computeOutlineNormalAttribute(mesh.geometry)
}
Defensive patterns

Strategy: validation

Validate before calling

if (!mesh.geometry.getAttribute(AIRI_OUTLINE_NORMAL_ATTRIBUTE_NAME)) {
  computeOutlineNormalAttribute(mesh.geometry) // re-run the geometry stage
}

Type guard

function hasOutlineNormal(geometry: BufferGeometry): boolean {
  return !!geometry.getAttribute(AIRI_OUTLINE_NORMAL_ATTRIBUTE_NAME)
}

Prevention

When it happens

Trigger: A mesh that bypassed the geometry-preparation pass (added/swap after registration), a geometry whose attribute computation failed silently, or non-standard geometry without the attributes the computation needs.

Common situations: Models with mixed rigging where some meshes skip the prepare hook; runtime mesh swapping; geometries missing normals so outlineNormal derivation was skipped.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/724edf23b3563629. Report an issue: GitHub.