Migration API "[ { property: 'title', error: 'The value must be a string' } ]"

Hi @alaina.koerber

Thanks for the work on the migration API. I think it will be great. The higher limit is very useful as it was tedious to upload each zip file every time. I also think it will become more automated now.

I am trying to migrate from one repo to another repository with multiple languages. I have several JSON files for each lang type. I have sent you an example of one type, for context: Switching from Nuxt 2 to Nextjs 14. Is it possible to have a "beta" Nextjs site and for it to work with Prismic Preview? - #10 by samlittlefair

I am using a demo key. I am trying to take the objects from the JSON files and add them to the new repo. I have only tried to get one document for now. If you could let me know where I have gone wrong that would be great, I am getting the error: [ { property: 'title', error: 'The value must be a string' } ]

There is no title on the new or old repo. There is no title in the json files.

import 'dotenv/config';
import fetch from 'node-fetch';

import { createRequire } from "module";
const require = createRequire(import.meta.url);
const data = require('./exports/export-ru-1.json')

async function init(doc) {
    const email = process.env.EMAIL;
    const password = process.env.PASSWORD;
    const repository = process.env.REPOSITORY_DEST;
    const apiKey = process.env.API_KEY;
    const url = `https://migration.prismic.io/documents/`;

    const authResponse = await fetch('https://auth.prismic.io/login', {
        headers: {
            'Content-Type': 'application/json',
        method: 'POST',
        body: JSON.stringify({
    const token = await authResponse.text();

    const response = await fetch(url, {
        headers: {
            Authorization: `Bearer ${token}`,
            'x-api-key': apiKey,
            'Content-Type': 'application/json',
        method: 'POST',
        body: JSON.stringify(doc),
    console.log(data, 'data');
    console.log(await response.json());

I sent you an example of the JSON file.

Thank you!

Hey @jjames.home thanks for reaching out.

This is an unclear error message that we could / should improve.
For each document creation we require you to have a title field outside of your data.

  "title" : "My Display Name", // The display Name of your doc
  "uid": "example-uid3", // New document UID
  "type": "blog", // A type that exists in your repository
  "lang": "en-us", // A locale that exists in your repository
  "data": {...} // The data based on your custom types

This title field is being used to provide a display name for your document in Prismic.
By adding this title field at the root of the JSON you should fix this issue.

Let me know if it works


Hi @renaud

Thanks for the reply. I will try it. It makes sense now.

Is it advised that I should always have a "title" outside of my data from now on? I am sure I used to set it to the same as the SEO title. Do I need to set it explicitly now?

I think it might be potentially confusing for content managers to have two titles that are abstracted from the normal content at least in the way I have it currently set up.


Hi @renaud

I used the uid for the title, but I have a new error! I am sure the old custom type UI created the heading JSON, not myself.

    property: 'data.body.0.items.0.heading.0.type',
    value: 'heading2',
    error: "The block type 'heading2' is not allowed in your document type. Enable the type for this rich text field to create the document."

Here is an example of the json data:

      "body": [
          "primary": {
            "heading": [
                "type": "heading2",
                "text": "heading text string is here",
                "spans": []
            "type": "small",
            "dimension": "default"
          }, .....

Here's the updated migration script

import 'dotenv/config';
import { createClient } from '@prismicio/client';
import fs from 'fs/promises';

const chunkArray = (array, size) => {
    return Array.from({ length: Math.ceil(array.length / size) }, (v, i) =>
        array.slice(i * size, i * size + size)

async function init(lang) {
    const client = createClient(process.env.REPOSITORY_SOURCE);
    const response = await client.dangerouslyGetAll({ lang: lang });

    const chunks = chunkArray(response, 100);

    await fs.mkdir('exports', { recursive: true })
    await Promise.all(chunks.map(async (chunk, index) => {

        const processedChunk = chunk.map(doc => {
            if (!doc.title) { 
                return { ...doc, title: doc.uid }; 
            return doc; 
        const fileName = `exports/export-${lang}-${index + 1}.json`;
        await fs.writeFile(fileName, JSON.stringify(processedChunk, null, 2))
        console.log(`Exported ${chunk.length} documents to ${fileName}`);