Skip to content

TypeError: Cannot read properties of undefined (reading 'include') — collections with empty source[] #425

@humanbird

Description

@humanbird

Bug

nuxt-studio@1.6.0 crashes when @nuxt/content v3 registers its internal info collection, which has source: [] (empty array). Studio's content listing code accesses source[0].include and source[0].prefix without checking if the array is empty, causing a TypeError that prevents the Studio editor from loading.

Reproduction

  1. Nuxt 4 + @nuxt/content v3.12.0 + nuxt-studio 1.6.0
  2. Define any content collections in content.config.ts (page or data type)
  3. Deploy with SSR and navigate to /_studio
  4. Browser console shows:
TypeError: Cannot read properties of undefined (reading 'include')
    at parseSourceBase (source.js)
    at Array.map
    at async Object.list
    at async Object.load (main-CUjoLU7k.js)

After patching parseSourceBase, the next crash is:

TypeError: Cannot read properties of undefined (reading 'prefix')
    at generateIdFromFsPath (collection.js)

Root Cause

@nuxt/content v3 creates an internal info collection in resolveCollections() (module.mjs:~2402):

collections.info = {
  type: "data",
  source: void 0, // no source
  // ...
};

The preview template serializes this as source: [] (empty array) via optional chaining fallback. When nuxt-studio iterates all collections and calls functions that access source[0], it crashes because source[0] is undefined.

Affected Files

dist/module/runtime/utils/source.js:

  • parseSourceBase(source) — line 5: source.include.includes("*") crashes when source is undefined
  • getCollectionSourceById() — line 15: source.prefix accessed without guard

dist/module/runtime/utils/collection.js:

  • generateIdFromFsPath() — line 10: collectionInfo.source[0] is undefined for empty source arrays
  • generateFsPathFromId() — line 17: parseSourceBase(source) called with undefined source

Suggested Fix

Add null guards before accessing source properties:

// source.js
export function parseSourceBase(source) {
  if (!source?.include) return { fixed: "", dynamic: "" };
  // ...existing code
}

// Inside getCollectionSourceById:
const matchedSource = sources.find((source) => {
  if (!source?.include) return false;
  // ...existing code
});

// collection.js
export function generateIdFromFsPath(path, collectionInfo) {
  if (!collectionInfo.source?.length) return join(collectionInfo.name, path);
  // ...existing code
}

export function generateFsPathFromId(id, source) {
  if (!source?.include) return id;
  // ...existing code
}

Workaround

Postinstall script that patches the affected files via string replacement:

// scripts/patch-nuxt-studio.mjs
import { readFileSync, writeFileSync } from 'fs'
import { resolve } from 'path'

const base = resolve('node_modules/nuxt-studio/dist/module/runtime/utils')

function patch(file, replacements) {
  const path = resolve(base, file)
  let content
  try { content = readFileSync(path, 'utf-8') } catch { return }
  let patched = false
  for (const [search, replace] of replacements) {
    if (content.includes(replace)) continue
    if (!content.includes(search)) { console.warn(`[patch] pattern not found in ${file}`); continue }
    content = content.replace(search, replace)
    patched = true
  }
  if (patched) { writeFileSync(path, content); console.log(`[patch] patched ${file}`) }
}

patch('source.js', [
  [
    'export function parseSourceBase(source) {\n  const [fixPart, ...rest] = source.include',
    'export function parseSourceBase(source) {\n  if (!source?.include) return { fixed: "", dynamic: "" };\n  const [fixPart, ...rest] = source.include'
  ],
  [
    'const matchedSource = sources.find((source) => {\n    const prefix = source.prefix;',
    'const matchedSource = sources.find((source) => {\n    if (!source?.include) return false;\n    const prefix = source.prefix;'
  ],
])

patch('collection.js', [
  [
    'export function generateIdFromFsPath(path, collectionInfo) {\n  const { fixed } = parseSourceBase(collectionInfo.source[0]);',
    'export function generateIdFromFsPath(path, collectionInfo) {\n  if (!collectionInfo.source?.length) return join(collectionInfo.name, path);\n  const { fixed } = parseSourceBase(collectionInfo.source[0]);'
  ],
  [
    'export function generateFsPathFromId(id, source) {\n  const [_, ...rest] = id.split',
    'export function generateFsPathFromId(id, source) {\n  if (!source?.include) return id;\n  const [_, ...rest] = id.split'
  ],
])

Add to package.json:

"postinstall": "node scripts/patch-nuxt-studio.mjs && nuxt prepare"

Environment

  • nuxt: 4.4.2
  • @nuxt/content: 3.12.0
  • nuxt-studio: 1.6.0
  • Node: 22.x / 24.x
  • Deployed on Vercel (SSR)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions