App owned Metaobject definitions in the TOML seem flakey

Hi team :waving_hand:

I’ve created an app owned metaobject definition in the TOML file which has been deployed to my development store and extension. When I query the metaobject definitions via GQL I can see it present in the results. But when I try to use it, for example by running a metaobjectUpsert mutation I get the response -

No metaobject definition exists for type "app--my_app_id--my_metaobject"

This was working yesterday but it seems that upon stopping the dev server and starting it again today something has been messed here, any advice would be much appreciated.

Hey Simon,

The “worked yesterday, broke after restart” part is telling. It seems your caller function changed underneath you.

Try passing $app:my_metaobjectas the type instead of app--<id>--my_metaobject.

The $app: form resolves against whichever app is authenticated on the request, so it can’t go stale. The expanded form is a snapshot of an app id, and the moment that id changes you get what you’re seeing: definition sitting there in query results, but upsert says “no can do partner.”

You can check the mutation, just run this next to the failing upsert:

{
  currentAppInstallation { app { id } }
  metaobjectDefinitionByType(type: "$app:my_metaobject") { id type }
}

If app { id } doesn’t match the number in the app--...-- type on the definition you’re seeing, then you’re calling as an app without ownership. That’s fine for reading, but writing, not so much. That’s why the query looks healthy and the upsert doesn’t.

If none of this is helping, let us know your setup, but a common use is the GraphiQL app in the
admin, where $app: resolves to GraphiQL, not to you, so it fails there no matter how correct
your app is.

If you’re wondering whether a dev server restart can change which app you’re upserting to, it can. I got burned by this when my ‘shopify app dev’ rewrote my prod ‘application_url’ in the partner dash, leaving it a mess though my repo hadn’t changed. Since partner dashbaord state is mutable, local tooling can change it without any alert, and the TOML in your repo suddenly stops being source of truth.

While in the TOML check that you have write_metaobjects and not
only write_metaobject_definitions.

If all of that didn’t help, again just post back, happy to help with any new issues related to this. Some other threads ran into orphaned entries from a definition that got deleted and recreated, and only Shopify can see that side. They will ask you for the X-Request-ID off the failing response if that’s the case.

Happy bug hunting!

Hi @cunningorb thanks heaps for your help here.

I should have provided some of the code I’m using, I am using the $app prefix everywhere instead of the app ID directly, that message is just what is returned when I attempt the upsert mutation, so after the $app prefix has been resolved I think.

I just checked, I do have both write_metaobject_definitions and write_metaobjects.

It’s weird I had the metaobject definition and an instance of it created for testing yesterday, it was all working, I don’t think I deployed anything in between, or switched branch so I can’t really explain why it’s all blown away today either. I’ve used GQL to define the metaobject definitions previously with none of these problems, I just wanted to use the TOML definition so I didn’t have to do a migration on all existing stores.

My definition in the TOML looks something like this:

[metaobjects.app.app_settings]
name = "App Settings"
description = "App store specific settings"
access.storefront = "public_read"
access.admin = "merchant_read"
capabilities.publishable = true

[metaobjects.app.app_settings.fields.storefront]
name = "Storefront"
type = "json"

And my upsert looks like this:

mutation UpsertMetaobject($handle: MetaobjectHandleInput!, $metaobject: MetaobjectUpsertInput!) {
  metaobjectUpsert(handle: $handle, metaobject: $metaobject) {
    metaobject {
      id
      values
    }
    userErrors {
      field
      message
    }
  }
}

Where $handle is

{
    "type": "$app:app_settings",
    "handle": "app_settings"
}

@simon_b Great detail! This narrows it down.

There’s a known issue where the definition gets deleted and recreated while the entries
don’t go with it, so they survive pointing at a definition id that no longer exists. The
upsert finds that orphan by handle and dies on the stale reference. Shopify’s own
explanation of it is here.
That one surfaces as an internal error rather than your message, so I can’t say for sure
it’s the same bug, but your story fits it exactly: it worked, an entry
exists, nothing in the repo changed, and a dev restart resynced the definition in between.

Two minute test. Run the same upsert with a handle you have never used, app_settings_v2 or
anything. If that goes through, the definition is fine and it’s the old entry that’s
poisoned.

Worth running this too, in the same authenticated context as the failing upsert and right
before it:

metaobjectDefinitionByType(type: "$app:app_settings") { id type }

Null there while your list query still shows the type means the resolution isn’t landing
where you think it is. An id back means the definition is healthy and it really is the
entry underneath it.

If the fresh handle works, the workaround people are using is a per-install suffix on the
handle until Shopify ships a fix. Orphans already sitting on the store can only be cleared
by Shopify support.

Post back either way, happy to keep digging.

@simon_b Great detail!

There’s a known issue where the definition gets deleted and recreated while the entries
don’t go with it, so they survive pointing at a definition id that no longer exists. The
upsert finds that orphan by handle and dies on the stale reference. Shopify’s own
explanation of it is here.
That one surfaces as an internal error rather than your message, so I can’t say for sure
it’s the same bug, but your story fits it exactly: it worked, an entry
exists, nothing in the repo changed, and a dev restart resynced the definition in between.

Two minute test. Run the same upsert with a handle you have never used, app_settings_v2 or
anything. If that goes through, the definition is fine and it’s the old entry that’s
poisoned.

Worth running this too, in the same authenticated context as the failing upsert and right
before it:

metaobjectDefinitionByType(type: "$app:app_settings") { id type }

Null there while your list query still shows the type means the resolution isn’t landing
where you think it is. An id back means the definition is healthy and it really is the
entry underneath it.

If the fresh handle works, the workaround people are using is a per-install suffix on the
handle until Shopify ships a fix. Orphans already sitting on the store can only be cleared
by Shopify support.

Post back either way, happy to keep digging. Or if you go shopify support route let us know on here how it went. I have had good experience with them.

Hi @simon_b, did you happen to uninstall the app and then reinstall before running that mutation?

Hi @Paige-Shopify thanks for having a look at this, it seems to be just some kind of glitch with my development environment, there were no uninstalls in between, I just stopped the dev server when I was done for the day.

Probably safe to ignore this one now, I’ve since deployed the TOML changes to production and all seems good.

No worries, thanks for letting me know. Feel free to flag it again in the event it pops up again.