{"record":{"id":"5a113addefc598b9","repo":"unionlabs/union","slug":"the-contentful-export-is-missing-the-landing-or-le","errorCode":null,"errorMessage":"The Contentful export is missing the landing or learn entry","messagePattern":"The Contentful export is missing the landing or learn entry","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"site/scripts/import-contentful-export.mjs","lineNumber":346,"sourceCode":"  return {\n    sourceId: item.sys.id,\n    createdAt: item.sys.createdAt,\n    updatedAt: item.sys.updatedAt,\n    firstPublishedAt: item.sys.firstPublishedAt ?? null,\n    publishedAt: item.sys.publishedAt ?? null,\n    published: publishedEntryIds.has(item.sys.id),\n  }\n}\n\nconst landingEntry = preview.entries.items.find(\n  (item) => entryType(item) === \"landing\",\n)\nconst learnEntry = preview.entries.items.find(\n  (item) => entryType(item) === \"learn\",\n)\n\nif (!landingEntry || !learnEntry) {\n  throw new Error(\n    \"The Contentful export is missing the landing or learn entry\",\n  )\n}\n\nconst landing = {\n  ...sourceMetadata(landingEntry),\n  entry: field(landingEntry, \"entry\") || \"\",\n}\nfor (const prefix of [\"first\", \"second\", \"third\", \"fourth\"]) {\n  landing[`${prefix}TitleHtml`] = renderTitle(\n    field(landingEntry, `${prefix}Title`),\n  )\n  landing[`${prefix}TextHtml`] = pageRichText(\n    field(landingEntry, `${prefix}Text`),\n  )\n}\nawait writeJson(join(dataDirectory, \"landing.json\"), landing)\n","sourceCodeStart":328,"sourceCodeEnd":364,"githubUrl":"https://github.com/unionlabs/union/blob/031785bb6dc6b957c624e62bc64c184409c97d7b/site/scripts/import-contentful-export.mjs#L328-L364","documentation":"The importer builds the site's core data from exactly one entry of content type \"landing\" and one of \"learn\" (entryType() reads sys.contentType.sys.id). If neither find() locates one of them in preview/entries.json, the script throws because every downstream artifact (hero titles, learn page) depends on those entries existing.","triggerScenarios":"The preview export's entries.items contains no item whose sys.contentType.sys.id is \"landing\" or \"learn\": wrong space or environment exported, the entries deleted in Contentful before the export was taken, content type IDs renamed in the content model, or a truncated/filtered entries.json.","commonSituations":"Passing a delivery directory where preview was expected, exporting with a space ID typo, a content-model refactor renaming the types, half-copied export directories, running the import against an export taken after the entries were unpublished.","solutions":["Inspect what the export actually contains: jq -r '[.items[].sys.contentType.sys.id] | unique | .[]' <preview-dir>/entries.json","Re-export the correct Contentful space/environment that still has the landing and learn entries","If the content model was renamed, update the entryType strings in the script in the same change","Verify previewDirectory and deliveryDirectory arguments both come from the same space"],"exampleFix":"// before\nconst landingEntry = preview.entries.items.find((item) => entryType(item) === \"landing\")\nconst learnEntry = preview.entries.items.find((item) => entryType(item) === \"learn\")\nif (!landingEntry || !learnEntry) {\n  throw new Error(\"The Contentful export is missing the landing or learn entry\")\n}\n\n// after — name what is missing and what exists\nconst present = [...new Set(preview.entries.items.map(entryType))]\nfor (const required of [\"landing\", \"learn\"]) {\n  if (!present.includes(required)) {\n    throw new Error(`Export has no \"${required}\" entry; content types present: ${present.join(\", \")}`)\n  }\n}","handlingStrategy":"validation","validationCode":"# Fail fast with actionable output before running the script\njq -r '[.items[].sys.contentType.sys.id] | unique | .[]' \"<preview-dir>/entries.json\"\n# both \"landing\" and \"learn\" must appear; if not, re-export the right space/environment","typeGuard":"const hasRequiredEntries = (entries) => {\n  const types = new Set(entries.items.map((item) => item.sys.contentType.sys.id))\n  return types.has(\"landing\") && types.has(\"learn\")\n}","tryCatchPattern":null,"preventionTips":["Export the same space and environment the site imports from","Keep content type IDs (landing, learn) stable, or update the script in the same change as any rename","Record the space/environment name in each archived export so mismatches are obvious","Run the jq check above in CI before the import step"],"tags":["contentful","content-import","validation","javascript"],"backgroundTag":null,"analyzedSha":"031785bb6dc6b957c624e62bc64c184409c97d7b","analyzedAt":"2026-08-16T06:24:09.996Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}