Environment
@unhead/schema-org: 2.1.12 (via nuxt-schema-org 6.0.4 / @nuxtjs/seo 5.0.2)
unhead: 2.1.12
- Node.js: v22
- Nuxt: 4.x
- Vue: 3.5.30
Reproduction
No repo link — the issue is visible directly in the source code and reproducible with any Nuxt app using defineWebSite with a SearchAction whose target is an object.
- In
app.vue, define a WebSite with a SearchAction using an object target (which the SearchAction type explicitly allows):
useSchemaOrg([
defineWebSite({
name: 'My Site',
url: siteUrl,
potentialAction: {
'@type': 'SearchAction',
'target': {
'@type': 'EntryPoint',
'urlTemplate': `${siteUrl}/search?q={search_term_string}`,
},
'query-input': {
'@type': 'PropertyValueSpecification',
'valueRequired': true,
'valueName': 'search_term_string',
},
},
}),
])
- Perform SPA navigation (e.g., click a
<NuxtLink> to another page and back).
- Observe the error in the browser console.
Describe the bug
During SPA navigation, the merge() function in @unhead/schema-org crashes with TypeError: byType[type].target is not iterable when merging duplicate potentialAction entries whose target is a plain object or string (not an array).
Root cause: In packages/schema-org/src/core/util.ts lines 38-39, the merge function spreads target assuming it's always an array:
if (action.target && byType[type].target)
byType[type].target = [...new Set([...byType[type].target, ...action.target])]
However, the SearchAction type definition (SearchAction/index.ts line 25-28) allows target to be a string or an EntryPoint object:
'target': SearchTarget | {
'@type'?: 'EntryPoint'
'urlTemplate'?: SearchTarget
}
And the resolver's own defaults (line 42-44) set target to an object:
defaults: {
'@type': 'SearchAction',
'target': { '@type': 'EntryPoint' },
}
So the types and the resolver both allow/produce non-array target, but the merge function crashes on it.
Suggested fix — normalize target to an array before spreading:
if (action.target && byType[type].target) {
const a = Array.isArray(byType[type].target) ? byType[type].target : [byType[type].target]
const b = Array.isArray(action.target) ? action.target : [action.target]
byType[type].target = [...new Set([...a, ...b])]
}
Workaround — wrap target in an array in user code:
'target': [{
'@type': 'EntryPoint',
'urlTemplate': `${siteUrl}/search?q={search_term_string}`,
}],
I'm happy to submit a PR with the fix + a regression test if this approach looks right.
Additional context
The error only occurs during SPA navigation (not on full page load or SSR), because that's when the same WebSite schema definition gets merged with itself as routes change. It does not appear in production when pages are server-rendered on each navigation.
Logs
Uncaught (in promise) TypeError: byType[type].target is not iterable
at merge (schema-org.BcpQpVeE.mjs:307:84)
at Object.resolveGraph (schema-org.BcpQpVeE.mjs:378:37)
at tags:resolve (schema-org.BcpQpVeE.mjs:677:43)
at async Object.resolveTags (unhead.Ct24BOby.mjs:141:7)
Environment
@unhead/schema-org: 2.1.12 (vianuxt-schema-org6.0.4 /@nuxtjs/seo5.0.2)unhead: 2.1.12Reproduction
No repo link — the issue is visible directly in the source code and reproducible with any Nuxt app using
defineWebSitewith aSearchActionwhosetargetis an object.app.vue, define aWebSitewith aSearchActionusing an objecttarget(which theSearchActiontype explicitly allows):<NuxtLink>to another page and back).Describe the bug
During SPA navigation, the
merge()function in@unhead/schema-orgcrashes withTypeError: byType[type].target is not iterablewhen merging duplicatepotentialActionentries whosetargetis a plain object or string (not an array).Root cause: In
packages/schema-org/src/core/util.tslines 38-39, the merge function spreadstargetassuming it's always an array:However, the
SearchActiontype definition (SearchAction/index.tsline 25-28) allowstargetto be a string or anEntryPointobject:And the resolver's own defaults (line 42-44) set
targetto an object:So the types and the resolver both allow/produce non-array
target, but the merge function crashes on it.Suggested fix — normalize
targetto an array before spreading:Workaround — wrap
targetin an array in user code:I'm happy to submit a PR with the fix + a regression test if this approach looks right.
Additional context
The error only occurs during SPA navigation (not on full page load or SSR), because that's when the same
WebSiteschema definition gets merged with itself as routes change. It does not appear in production when pages are server-rendered on each navigation.Logs
Uncaught (in promise) TypeError: byType[type].target is not iterable at merge (schema-org.BcpQpVeE.mjs:307:84) at Object.resolveGraph (schema-org.BcpQpVeE.mjs:378:37) at tags:resolve (schema-org.BcpQpVeE.mjs:677:43) at async Object.resolveTags (unhead.Ct24BOby.mjs:141:7)