Debugging inconsistency with Vision Plugin and draft titles in Sanity.io

14 replies
Last updated: Aug 20, 2020
Hi! Can someone help me debug a strange inconsistency I'm encountering?Using the Vision Plugin, I cannot get the draft for one type of document, but I can for other types.
This query *[_type == "page" && slug.current == "about"][0].title doesn't get me the draft title, only the published title.
But this query *[_type == "event" && slug.current == "meet-up"][0].title does gives me the draft title, as expected
So puzzling
🤔
AI Update

This is likely a perspective issue with the Vision plugin! The Vision plugin uses a specific perspective when querying, and this can affect whether you see draft or published content.

The key issue is that the Vision plugin's default perspective behavior has changed. As of the API version 2025-02-19, the default perspective changed from raw to published. This means queries will only return published documents unless you explicitly specify a different perspective.

However, the inconsistency you're seeing between document types suggests something else might be at play. Here are the most likely causes:

1. Check the Vision plugin's perspective setting

In the Vision plugin interface, there should be a perspective dropdown (usually in the top right). Make sure it's set to either:

  • previewDrafts - Shows drafts when they exist, falls back to published
  • raw - Shows all documents including both drafts and published versions

2. Your "page" document might not have a draft

This is the most common cause of this exact behavior. If you're seeing the published title for your "page" document but the draft title for your "event" document, it's possible that:

  • The "event" document has actual unpublished changes (a drafts. version exists)
  • The "page" document's draft was already published, so only the published version exists

You can verify this by checking if a draft exists:

*[_id == "drafts.page-about"]

If this returns nothing, there's no draft version to retrieve.

3. Explicitly query for drafts

If you want to ensure you're getting the draft when it exists, you can use the draft-or-published pattern:

*[_type == "page" && slug.current == "about"]
  | score(_id in path("drafts.**"))
  | order(_score desc)[0].title

This prioritizes drafts but falls back to published versions when no draft exists.

The most likely explanation is that your "page" document simply doesn't have unpublished changes at the moment, while your "event" document does. Try making an edit to the "page" document without publishing it, then run your query again in Vision - you should see the draft title appear.

You can read more about how perspectives work and how Sanity handles draft documents in the documentation.

That’s very puzzling…. Just tested against my local copy of the movie data set and Vision is pulling my draft title… when you run
*[_type == "page" && slug.current == "about"][0]
do you get the draft id?
yes, it also works fine for me with the movie dataset.But not for this project.
No, I don't get the draft id.
Checking a quick assumption: does your Page document have
liveEdit: true
?
no liveEdit
this is the document JS file:

import { FaCopy } from 'react-icons/fa'

import conditionalFields from '../../components/conditionalFieldsCustomInputComponent'

export default {
  name: 'page',
  title: 'Seiten',
  type: 'document',
  icon: FaCopy,
  fieldsets: [
    {
      title: 'Banner-Bild auf Mobile',
      name: 'mobile',
      options: { collapsible: true },
    },
  ],
  fields: [
    {
      name: 'title',
      title: 'Titel',
      type: 'string',
      validation: (Rule) => Rule.required().error('Pflichtfeld'),
    },
    {
      name: 'body',
      type: 'object',
      inputComponent: conditionalFields,
      fields: [
        {
          name: 'richText',
          title: 'Body',
          type: 'blockContent',
        },
      ],
    },
    {
      title: 'Desktop Banner-Bild',
      name: 'heroImage',
      type: 'image',
      description: 'Bildschirmbreite einnehmendes Bild',
      validation: (Rule) => Rule.required().error('Pflichtfeld'),
      options: {
        hotspot: true,
        metadata: ['lqip'],
      },
      fields: [
        {
          name: 'alt',
          type: 'string',
          title: 'Alternativer Text',
          validation: (Rule) => Rule.required().error('Pflichtfeld'),
          description:
            'Bildbeschreibung für Barrierefreiheit und Suchmaschinenoptimierung',
          options: {
            isHighlighted: true,
          },
        },
      ],
    },
    {
      title: 'Mobile Banner-Bild',
      name: 'mobileHeroImage',
      type: 'image',
      description: 'Bildschirmbreite einnehmendes Bild',
      fieldset: 'mobile',
      options: {
        hotspot: true,
        metadata: ['lqip'],
      },
    },
    {
      name: 'slug',
      type: 'slug',
      title: 'Titelform in URL',
      description: 'Für die Home-Seite nur einen Schrägstrich erfassen.',
      validation: (Rule) => Rule.required().error('Pflichtfeld'),
      options: {
        source: 'title',
        maxLength: 96,
      },
    },
    {
      name: 'description',
      title: 'Kurze Beschreibung von der Seite',
      description: 'Wird im Suchresultat von Google angezeigt.',
      validation: (Rule) => [
        Rule.max(300).warning(
          'Die Beschreibung sollte kürzer als 300 Zeichen sein'
        ),
      ],
      type: 'text',
      rows: 1,
    },
  ],
}
This is bugging me…. i brought your schema into my local project and it’s not grabbing the draft… i reduced it to a test case of just title and slug… it’s not anything i can think of. I’ll poke a couple people and see if i can get it figured out
It’s gonna bug me until i figure it out
yeah, I was also going to remove fields until it works. so even with only a title and a slug, it doesn’t work?let me know if you need that I invite you into the project.
Just title and slug. In one of my local testing studios...
how strange 😮
(if I edit the slug to “about-2” and fetch by slug.current == “about-2". I do get the draft)
Got to the root of this,
user E
! by calling
[0]
you’re only getting the first item in that array. If you look at the documents in the result, you should see 2 documents. The default ordering is alphanumeric 0-9a-z.
In my
movie
dataset, all my movie documents have an id that starts with
movie
and drafts start with
drafts.movie
so the draft was always first. There’s a chance the randomly generated _id strings could result in drafts coming first, but often they won’t. So if you want the draft version of the doc, you’ll need to check to see if the id starts with draft
Oh! Thanks for figuring that out! 😃That's why I was also always getting the draft first in the movie dataset.
I'm going to change my query to this in order to be sure to always get the draft first if there's one:*[_type == "page" && slug.current == $slug] | order(_updatedAt desc)[0]

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?