CDN URLs Missing from Referenced Documents - Urgent Production Issue

11 replies
Last updated: Feb 13, 2024
Dear Sanity team,
We are experiencing a serious issue on our audiobook app which seems to be caused by Sanity and is currently preventing all of our users from downloading new audiobooks on the app. For this reason we would really appreciate a quick response.

All of a sudden our cdn downloads don't respond with the entities that we expect, which leads to un-downloadable content for our users.

After lengthy investigations over the weekend we discovered that the illustrations array and the respective illustration object does not contain the cdn url anymore. This means our illustration images can not be resolved.
The references do not work, meaning that anything that is referenced in another document seems to no longer be resolved.

We have not changed anything on our side. We have not changed the Sanity studio version nor the GROQ query. The issue described is happening on both our production and staging apps, on both Android and iOS.

For now we have reached the conclusion that something might have changed on Sanity's side? Has anything GROQ related deprecated? All the other assets can be loaded smoothly.

I hope you understand how urgent and potentially damaging this is for our business - we'd really appreciate some support! Thank you.
AI Update

I completely understand the urgency of this situation - having your users unable to download audiobooks is a critical issue. Let me help you troubleshoot this systematically.

Most Likely Cause: API Version Configuration

Based on your symptoms (references suddenly not resolving, missing CDN URLs in illustration objects), the most probable cause is related to how your Sanity client is configured, particularly around API versioning.

What May Have Changed

If you weren't explicitly setting an apiVersion in your Sanity client configuration, your application may have started defaulting to a newer API version. Sanity uses a date-based API versioning system, and when no version is specified, the behavior can change when new versions are released.

The most recent API version (v2025-02-19, released February 24, 2025) includes a significant change: the default perspective switched from raw to published. Depending on when you're experiencing this issue, this could be relevant - but regardless, the principle remains the same for any API version change.

Immediate Fix Options

Option 1: Explicitly lock to a stable API version (fastest way to restore service):

const client = createClient({
  projectId: 'your-project-id',
  dataset: 'your-dataset',
  apiVersion: '2024-05-01', // or another stable date you know worked
  useCdn: true,
})

Option 2: Explicitly set the perspective to raw:

const client = createClient({
  projectId: 'your-project-id',
  dataset: 'your-dataset',
  apiVersion: '2024-05-01', // use a specific version
  perspective: 'raw', // explicitly request all content including drafts
  useCdn: true,
})

Additional Troubleshooting Steps

  1. Check your illustration documents' publish status: In Sanity Studio, verify that all referenced illustration documents are actually published (not just saved as drafts). If your queries are now using a published perspective, they won't resolve references to draft-only documents.

  2. Verify your GROQ query structure: Make sure your query properly dereferences the asset reference. A working query should look something like:

    *[_type == "audiobook"] {
      title,
      illustrations[]-> {
        _id,
        title,
        asset-> {
          _id,
          url
        }
      }
    }
  3. Check all client instances: Verify that ALL places where you instantiate Sanity clients (frontend, backend, iOS app, Android app) have the same configuration. An inconsistency here could explain why it's affecting all platforms.

  4. Review Sanity's status page: Visit status.sanity.io to check for any ongoing service incidents or outages.

  5. Inspect the actual data structure: Use Sanity's Vision plugin in your Studio to run your query and see exactly what data structure is being returned. This will help confirm whether the issue is with the query, the data structure, or the client configuration.

Why References Might Not Resolve

The Image Pipeline serves images through cdn.sanity.io URLs that are constructed from asset references. When references don't resolve properly, the asset object (which contains the url field) won't be included in your query results. This typically happens when:

  • The perspective setting doesn't match your content's publish state
  • The GROQ query doesn't properly dereference the reference (missing ->)
  • The referenced documents don't exist or aren't accessible with the current query configuration

Next Steps

  1. Deploy the fix immediately - add explicit apiVersion to all your Sanity client configurations
  2. Test on staging first if possible, but given the urgency, you may need to go straight to production
  3. Monitor the results - check if audiobooks become downloadable again
  4. Document your configuration - ensure your apiVersion is explicitly set going forward to prevent automatic upgrades

The fix should be a quick configuration change that you can deploy across all platforms. Since you mentioned this is affecting both production and staging identically, and you haven't changed anything on your side, this strongly suggests an API version or configuration issue rather than a code bug.

Please try these fixes and let me know if this resolves the issue. If not, share your GROQ query and client configuration (with sensitive data removed) so we can dig deeper!

Show original thread
11 replies
Query:`const bookListFields = ``
"slug": slug.current,
"bookSample": bookSample.asset -> {url, size},
themes[] ->,
categories[] ->,
creators[] -> {
...,
"portrait": portrait.asset -> {url, size}
},
"illustration": illustrations[0] -> {
...image.asset -> {url, size},
altText
}


const booksQuery = 
*[_type == "book" ${territoryCondition} && (
"user" in access[].roleName ||
$role in access[].roleName ||
$email in access[].emailAddress
)]{
...,
${bookListFields}
}
`

const resolveImageOrIllustration =
{
    _type == "image" => {
      altText,
      ...asset -> {size, url}
    },
    _type == "illustration" => @-> {
      ...image.asset-> {size, url},
      altText
    },
    _type == "creator" => @-> {
      ...portrait.asset-> {size, url},
      altText
    }
 }

const fetchBookDetailsQuery = `
*[_type == "book" && _id == $id]{
...,
${bookListFields},
characters[] ->,
chapters[] -> {
...,
"illustration": illustration[0]${resolveImageOrIllustration},
"notes": notes[]->{
...,
_type == "imageNote" => {
...,
"image": image[0]${resolveImageOrIllustration}
},
_type == "audioNote" => {
...,
"audio": track.asset -> {url, size}
},
_type == "textNote" => {...},
_type == "videoNote" => {...},
_type == "spotifyNote" => {...}
},
"audio": audio.asset -> {url, size}
}
}
👋 I asked for more information about specific error logs in a thread that another member of your team posted, but haven’t gotten them yet. I received a response with a description of what had been tried, but I can’t help you diagnose your issue with that, unfortunately. As I said, I’ve checked on our end and we’re not blocking your project. There also aren’t any changes to GROQ that I’m aware of, but I will ask internally.
In the mean time, can you also share how your client is configured and the version you’re using?
Hi rd,
we don't have any specific Sanity related logs regarding the issue, only errors, that we throw, when something does not work like the download.

Also: the issue did resolve without us doing anything. Did you experience any data loss and recovered those? Otherwise I can not explain, why it suddenly would not work and suddenly work. To me it seems like a weekend bug, that was resolved yesterday evening (morning on your side of the world).

Our client:
We do use Sanity as PicoSanity version: 4.1.1 in our Expo managed React Native application.
This is the config:

import PicoSanity from 'picosanity'

import config, {getEnvironment} from '../config'

export const sanityClient = PicoSanity({
  projectId: config.sanity.projectId,
  dataset: config.sanity.dataset,
  apiVersion: '2022-06-05', // use current UTC date - see "specifying API version"!
  useCdn: getEnvironment() === 'production',
})

export const fetch = (query: string, args: Args) =>
  sanityClient.fetch(query, args)

type ArgsPrimitives = string | null | number | boolean
type Args = Record<string, ArgsPrimitives | ArgsPrimitives[]>

export const fetchMulti = <T extends string>(
  queries: Record<T, string>,
  args: Args
) => {
  const query = Object.entries(queries)
    .map(([name, query]) => `'${name}': ${query}`)
    .join(',\n')

  return sanityClient.fetch(`{${query}}`, args)
}
'Our Sanity Studio is version
3.6.0
. The latest version is `3.28.0`'
We did not experience any outages or data loss and you are the only person to report behavior such as this. I strongly suspect it was something on your side. Without knowing error codes or logs, there’s not much I can do to diagnose your issue.
Oh, can you also share where you are? It may be helpful as we investigate.
So the company is based in London Great Britain, I do work from Hamburg.The app is used in all over the world
Would you be able to share a link to a query that gave this behavior?
Ok, I tracked down the behavior. A change was rolled out over the weekend to free plans that changed the way that references were resolved on the backend. The scope of this was not made clear to me and I apologize that you experienced it. It has been turned off.
Hi rd! Thank you very much for tracking it down, I was able to identify, that our references haven’t been resolved but I was not able to find anything on our side.
I’m happy that it was resolved, but how can we make sure, that it doesn’t happen again?

Also one question: we are considering to move to the payed plan. Does this change anything in regard of our data fetching? Is there anything to consider for our production environment?
Hopefully, in the future we don’t decide to roll out changes to our backend over the weekend without notifying everyone that it’s going to happen. A paid plan won’t change your data fetching behavior. It’ll all still operate the same under the hook. Paid plans mostly unlock things like more quota and extra collaboration features. Things like an Enterprise plan include guaranteed uptime and dedicated support.

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?