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

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions