`slug` is `undefined` when I track mark and children from internalLink

4 replies
Last updated: Jan 27, 2026
I’m getting this from my console when I track
mark
and
children
from
internalLink
:
internalLink - mark 
_key: "7e6ceaaccca5"
_type: "internalLink"
reference: {…}
    _ref: "6230af03-9c14-4316-aa6f-ba7903d72c51"
    _type: "reference"

internalLink - children 
_key: "7e6ceaaccca5"
_type: "internalLink"
reference: {…}
    _ref: "6230af03-9c14-4316-aa6f-ba7903d72c51"
    _type: "reference"

slug
is
undefined
... arrrgh!What ... am I doing wrong?!
AI Update

The issue you're experiencing is that you're looking at the annotation object itself (which only contains the reference ID), but you need to resolve the reference to get the actual document data including the slug.

When you see reference: { _ref: "6230af03-9c14-4316-aa6f-ba7903d72c51" }, that's just a pointer to another document. The slug lives in the referenced document, not in the annotation object.

The Solution: Use GROQ to Expand References

You need to use GROQ's reference expansion operator (->) to fetch the actual document data. Here's how:

*[_type == "yourDocType"] {
  content[] {
    ...,
    markDefs[] {
      ...,
      _type == "internalLink" => {
        ...,
        "slug": reference->slug.current,
        "title": reference->title
      }
    }
  }
}

This tells GROQ to follow the reference and grab the slug from the referenced document.

If You're Rendering on the Frontend

If you're working with already-fetched data and need to resolve references client-side, you have a few options:

Option 1: Fetch with proper projection (recommended) Make sure your initial GROQ query expands the reference as shown above.

Option 2: Custom serializer with additional fetch If you're using @portabletext/react or similar, you can create a custom mark component that fetches the referenced document:

const components = {
  marks: {
    internalLink: ({value, children}) => {
      // value.reference._ref exists, but you need to fetch the document
      // OR better yet, ensure your GROQ query already expanded it
      const href = value.slug || '#'
      return <a href={href}>{children}</a>
    }
  }
}

Why This Happens

Sanity uses references to avoid data duplication and maintain referential integrity. The annotations documentation shows that internal link annotations store a reference object, not the full document data. You must explicitly tell GROQ to expand that reference using the -> operator.

The key takeaway: references are pointers, not the actual data. Always use -> in your GROQ queries to dereference them!

Show original thread
4 replies

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?