Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.0.0-beta.30] Error: Only plain objects, and a few built-ins, can be passed to Client Components from Server Components #6351

Open
mixty1 opened this issue May 14, 2024 · 5 comments
Assignees
Labels
status: needs-repro If an issue does not include a reproduction v3

Comments

@mixty1
Copy link

mixty1 commented May 14, 2024

Link to reproduction

No response

Describe the Bug

update version from 3.0.0-beta.24 to 3.0.0-beta.30 and get some errors

key not found:  upload:Sizes
 ⨯ Error: Only plain objects, and a few built-ins, can be passed to Client Components from Server Components. Classes or null prototypes are not supported.
    at stringify (<anonymous>)
    at stringify (<anonymous>)
digest: "1852293969"
 ⨯ Error: Only plain objects, and a few built-ins, can be passed to Client Components from Server Components. Classes or null prototypes are not supported.
    at stringify (<anonymous>)
    at stringify (<anonymous>)
    at stringify (<anonymous>)
    at stringify (<anonymous>)
digest: "1371415116"
 ⨯ Internal error: TypeError: Cannot read properties of null (reading 'digest')
    at Object.onError (/Users/{{projectFolder}}/node_modules/.pnpm/next@14.3.0-canary.28_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.76.0/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:36:17945)
    at al (/Users/{{projectFolder}}/node_modules/.pnpm/next@14.3.0-canary.28_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.76.0/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:9931)
    at /Users/{{projectFolder}}/node_modules/.pnpm/next@14.3.0-canary.28_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.76.0/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:59036
    at /Users/{{projectFolder}}/node_modules/.pnpm/next@14.3.0-canary.28_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.76.0/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:59252
    at aA (/Users/{{projectFolder}}/node_modules/.pnpm/next@14.3.0-canary.28_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.76.0/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:59260)
    at Timeout._onTimeout (/Users/{{projectFolder}}/node_modules/.pnpm/next@14.3.0-canary.28_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.76.0/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:6971)
    at listOnTimeout (node:internal/timers:573:17)
    at process.processTimers (node:internal/timers:514:7)
digest: "2263670172"
 GET /admin 500 in 9698ms
 ⨯ Error: Attempted to call useWatchForm() from the server but useWatchForm is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.
    at /Users/{{projectFolder}}/.next/server/chunks/ssr/3bbea_@payloadcms_ui_dist_e5e06c._.js:1181:11
    at LinkToDoc (/Users/{{projectFolder}}/.next/server/chunks/ssr/node_modules__pnpm_35a647._.js:13319:414)
    at stringify (<anonymous>)
digest: "323871085"
 ✓ Compiled in 1669ms
 ✓ Compiled /admin/[[...segments]] in 22ms
key not found:  upload:Sizes
 ⨯ Error: Only plain objects, and a few built-ins, can be passed to Client Components from Server Components. Classes or null prototypes are not supported.
    at stringify (<anonymous>)
    at stringify (<anonymous>)
digest: "1852293969"
 ⨯ Error: Only plain objects, and a few built-ins, can be passed to Client Components from Server Components. Classes or null prototypes are not supported.
    at stringify (<anonymous>)
    at stringify (<anonymous>)
    at stringify (<anonymous>)
    at stringify (<anonymous>)
digest: "1371415116"
 ⨯ Error: Attempted to call useWatchForm() from the server but useWatchForm is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.
    at /Users/{{projectFolder}}/.next/server/chunks/ssr/3bbea_@payloadcms_ui_dist_e5e06c._.js:1181:11
    at LinkToDoc (/Users/{{projectFolder}}/.next/server/chunks/ssr/node_modules__pnpm_35a647._.js:13319:414)
    at stringify (<anonymous>)
digest: "323871085"
 ⨯ Internal error: TypeError: Cannot read properties of null (reading 'digest')
    at Object.onError (/Users/{{projectFolder}}/node_modules/.pnpm/next@14.3.0-canary.28_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.76.0/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:36:17945)
    at al (/Users/{{projectFolder}}/node_modules/.pnpm/next@14.3.0-canary.28_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.76.0/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:9931)
    at /Users/{{projectFolder}}/node_modules/.pnpm/next@14.3.0-canary.28_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.76.0/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:59036
    at /Users/{{projectFolder}}/node_modules/.pnpm/next@14.3.0-canary.28_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.76.0/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:59252
    at aA (/Users/{{projectFolder}}/node_modules/.pnpm/next@14.3.0-canary.28_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.76.0/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:59260)
    at Timeout._onTimeout (/Users/{{projectFolder}}/node_modules/.pnpm/next@14.3.0-canary.28_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.76.0/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:6971)
    at listOnTimeout (node:internal/timers:573:17)
    at process.processTimers (node:internal/timers:514:7)
digest: "2263670172"
 GET /admin 500 in 204ms

I have many collections and this part of error – key not found: upload:Sizes comes from my Media collection for uploading images, and it's have field imageSizes, if i remove this field, key not found: upload:Sizes is gone, but i need this field. I don't know yet how to fix other errors, because before this version all was ok. And unfortunately i can't reproduce all structure of my app, but i have typical structure for e-commerce.

To Reproduce

install payload@3.0.0-beta.30 @payloadcms/db-postgres@3.0.0-beta.30 @payloadcms/next@3.0.0-beta.30 @payloadcms/plugin-nested-docs@3.0.0-beta.30 @payloadcms/plugin-search@3.0.0-beta.30 @payloadcms/richtext-slate@3.0.0-beta.30 @payloadcms/ui@3.0.0-beta.30 @payloadcms/translations@3.0.0-beta.30 and load admin main page

Payload Version

3.0.0-beta.30

Adapters and Plugins

db-postgres, plugin-nested-docs, plugin-search, richtext-slate

@mixty1 mixty1 added the status: needs-triage Possible bug which hasn't been reproduced yet label May 14, 2024
@jmikrut
Copy link
Member

jmikrut commented May 14, 2024

Hey - we will need a minimal reproduction in order to help you here. Can we see your config? And your collection configs where upload is enabled?

@mixty1
Copy link
Author

mixty1 commented May 14, 2024

Hey! Thx for quick response, ok i can show config and some collections code.

// payload.config.ts

import path from 'path'
import sharp from 'sharp'
import { fileURLToPath } from 'url'
import { en } from 'payload/i18n/en'
import { ru } from 'payload/i18n/ru'
import { buildConfig } from 'payload/config'
import { slateEditor } from '@payloadcms/richtext-slate'
import { postgresAdapter } from '@payloadcms/db-postgres'
import { nestedDocsPlugin } from '@payloadcms/plugin-nested-docs'
import { searchPlugin } from '@payloadcms/plugin-search'

import Users from './src/collections/Users'
import Products from './src/collections/Products'
import Categories from './src/collections/Categories'
import Tags from './src/collections/Tags'
import Media from './src/collections/Media'
import SpecGroup from './src/collections/SpecGroup'
import SpecName from './src/collections/SpecName'
import SpecValue from './src/collections/SpecValue'
import ProductSpecs from './src/collections/ProductSpecs'
import Pages from './src/collections/Pages'
import Widgets from './src/collections/Widgets'
import Orders from './src/collections/Orders'

const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)

export default buildConfig({
  cors: process.env.NODE_ENV === 'production' ? undefined : '*',
  admin: {
    user: Users.slug,
    // css: path.resolve(__dirname, './src/assets/styles/base.scss'),
    // bundler: viteBundler(),
  },
  editor: slateEditor({}),
  collections: [
    Users,
    Products,
    Categories,
    Tags,
    Media,
    ProductSpecs,
    SpecGroup,
    SpecName,
    SpecValue,
    Pages,
    Widgets,
    Orders,
  ],
  secret: process.env.PAYLOAD_SECRET || '',
  typescript: {
    outputFile: path.resolve(dirname, 'payload-types.ts'),
  },
  plugins: [
    // payloadCloud(),
    searchPlugin({
      collections: [Products.slug],
      searchOverrides: {
        admin: {
          hidden: true,
        },
      },
    }),
    nestedDocsPlugin({
      collections: [Categories.slug],
      generateURL: (docs) => docs.reduce((_, doc) => `/catalog/${doc.slug}`, ''),
    }),
  ],
  db: postgresAdapter({
    pool: {
      connectionString: process.env.DATABASE_URI,
    },
  }),
  i18n: {
    supportedLanguages: { en, ru },
  },
  sharp,
})
// src/collections/Media.ts
import { CollectionConfig } from 'payload/types'

const Media: CollectionConfig = {
  slug: 'media',
  access: {
    read: () => true,
    create: () => true,
  },
  labels: {
    singular: {
      en: 'Media',
      ru: 'Медиа',
    },
    plural: {
      en: 'Media',
      ru: 'Медиа',
    },
  },
  fields: [
    {
      name: 'alt',
      type: 'text',
    },
  ],
  upload: {
    staticDir: 'media',
    imageSizes: [
      {
        name: 'thumbnail',
        width: 256,
        height: 256,
        position: 'centre',
      },
      {
        name: 'card',
        width: 512,
        height: 512,
        position: 'centre',
      },
      {
        name: 'tablet',
        width: 1024,
        height: 1024,
        position: 'centre',
      },
      {
        name: 'banner',
        width: 1256,
        height: 400,
        position: 'centre',
      },
    ],
    adminThumbnail: 'thumbnail',
    mimeTypes: ['image/*'],
  },
}

export default Media

@r1tsuu
Copy link
Contributor

r1tsuu commented May 14, 2024

i can't see it from your code, but if you somewhere have something like this with custom component

Field: (props) => <Component {...props} />

And Component is client component, then you'll get this error. Because there was a breaking change, that also was actually a fix with passing payload into custom component. You need to delete payload key before passing it

Field: ({ payload: _payload, ...props }) => <Component {...props} />

@mixty1
Copy link
Author

mixty1 commented May 14, 2024

Yes, i have custom components in my Products collection which has client-only components, but if i comment lines with this components, errors doesn't gone.

I tried like you say:

Field: ({ payload: _payload, ...props }) => <Uppy {...props} />,

Field: ({ payload: _payload, ...props }) => <SpecList {...props} />,

but it's not working.

Products collection:

// src/collections/Products.ts

import { CollectionConfig } from 'payload/types'
import Tags from '../Tags'
import ProductSpecs from '../ProductSpecs'
import SpecList from './ui/SpecList'
import SpecGroup from '../SpecGroup'
import SpecName from '../SpecName'
import SpecValue from '../SpecValue'
import productSpecsHook from './hooks/product-specs'
import productMediaHook from './hooks/product-media'
// import initSpecsHook from './hooks/init-specs'
// import validateSpecs from './validations/validate-specs'
import Uppy from '../../app/(payload)/components/Uppy'
import Media from '../Media'
import SaveButton from './ui/SaveButton'
import generateSlug from '../hooks/generate-slug'

const Products: CollectionConfig = {
  slug: 'products',
  access: {
    read: () => true,
    create: () => true,
    update: () => true,
  },
  hooks: {
    beforeOperation: [generateSlug],
  },
  admin: {
    useAsTitle: 'title',
    components: {
      edit: {
        SaveButton,
      },
    },
  },
  labels: {
    singular: {
      en: 'Product',
      ru: 'Товар',
    },
    plural: {
      en: 'Products',
      ru: 'Товары',
    },
  },
  fields: [
    {
      name: 'title',
      type: 'text',
      required: true,
      label: {
        en: 'Title',
        ru: 'Название',
      },
    },
    {
      name: 'slug',
      type: 'text',
      unique: true,
      admin: {
        hidden: true,
      },
      label: {
        en: 'Slug',
        ru: 'Строка',
      },
    },
    {
      name: 'hero',
      type: 'upload',
      relationTo: 'media',
      required: true,
      label: {
        en: 'Hero',
        ru: 'Изображение',
      },
    },
    {
      name: 'category',
      type: 'relationship',
      required: true,
      relationTo: 'categories',
      hasMany: false,
      admin: {
        position: 'sidebar',
      },
      label: {
        en: 'Catergory',
        ru: 'Категория',
      },
    },
    {
      name: 'sku',
      type: 'text',
      required: true,
      unique: true,
      admin: {
        position: 'sidebar',
      },
      label: {
        en: 'Sku',
        ru: 'Артикул',
      },
    },
    {
      name: 'stock',
      type: 'number',
      defaultValue: 0,
      required: true,
      admin: {
        position: 'sidebar',
      },
      label: {
        en: 'Stock',
        ru: 'Наличие',
      },
    },
    {
      name: 'status',
      type: 'text',
      admin: {
        position: 'sidebar',
      },
      label: {
        en: 'Status',
        ru: 'Статус',
      },
    },
    {
      name: 'prices',
      type: 'group',
      interfaceName: 'Prices',
      label: {
        en: 'Prices',
        ru: 'Цены',
      },
      admin: {
        position: 'sidebar',
      },
      fields: [
        {
          name: 'retail',
          type: 'number',
          required: true,
          label: {
            en: 'Retail',
            ru: 'Розничная цена',
          },
        },
        {
          name: 'purchase',
          type: 'number',
          label: {
            en: 'Purchase',
            ru: 'Оптовая цена',
          },
        },
        {
          name: 'discount',
          type: 'number',
          label: {
            en: 'Discount',
            ru: 'Скидка',
          },
        },
        {
          name: 'currency',
          type: 'text',
          required: true,
          defaultValue: '₸',
          label: {
            en: 'Currency',
            ru: 'Валюта',
          },
        },
      ],
    },
    {
      name: 'description',
      type: 'richText',
      label: {
        en: 'Description',
        ru: 'Описание',
      },
    },
    {
      name: 'media',
      type: 'relationship',
      relationTo: Media.slug,
      hasMany: true,
      label: {
        en: 'Media',
        ru: 'Медиа файлы',
      },
      admin: {
        components: {
          Field: Uppy,
        },
      },
      // hooks: {
      //   beforeChange: [productMediaHook],
      // },
    },
    {
      name: 'productspecs',
      type: 'relationship',
      relationTo: ProductSpecs.slug,
      hasMany: true,
      label: {
        en: 'Specifications',
        ru: 'Характеристики',
      },
      admin: {
        custom: {
          fields: [
            {
              name: 'group',
              type: 'ui',
              custom: {
                collection: SpecGroup.slug,
              },
              label: {
                en: 'Group',
                ru: 'Группа',
              },
            },
            {
              name: 'name',
              type: 'ui',
              custom: {
                collection: SpecName.slug,
              },
              label: {
                en: 'Name',
                ru: 'Название',
              },
            },
            {
              name: 'value',
              type: 'ui',
              custom: {
                collection: SpecValue.slug,
              },
              label: {
                en: 'Value',
                ru: 'Значение',
              },
            },
          ],
        },
        components: {
          Field: SpecList,
        },
      },
      hooks: {
        beforeChange: [productSpecsHook],
        // afterRead: [initSpecsHook]
      },
      // validate: validateSpecs,
    },
    {
      name: 'dimensions',
      type: 'group',
      interfaceName: 'Dimensions',
      admin: {
        className: 'product-dimensions',
      },
      label: {
        en: 'Dimensions (mm)',
        ru: 'Размеры (мм)',
      },
      fields: [
        {
          name: 'width',
          type: 'number',
          admin: {
            width: '24%',
          },
          label: {
            en: 'Width',
            ru: 'Ширина',
          },
        },
        {
          name: 'height',
          type: 'number',
          admin: {
            width: '24%',
          },
          label: {
            en: 'Height',
            ru: 'Высота',
          },
        },
        {
          name: 'length',
          type: 'number',
          admin: {
            width: '24%',
          },
          label: {
            en: 'Length',
            ru: 'Длина',
          },
        },
        {
          name: 'weight',
          type: 'number',
          admin: {
            width: '24%',
          },
          label: {
            en: 'Weight',
            ru: 'Вес',
          },
        },
      ],
    },
    {
      name: 'model',
      type: 'text',
      label: {
        en: 'Model',
        ru: 'Модель',
      },
    },
    {
      name: 'manufacturer',
      type: 'text',
      label: {
        en: 'Manufacturer',
        ru: 'Производитель',
      },
    },
    {
      name: 'country',
      type: 'text',
      label: {
        en: 'Country',
        ru: 'Страна',
      },
    },
    {
      name: 'isVisible',
      defaultValue: true,
      type: 'checkbox',
      label: {
        en: 'Visiblity',
        ru: 'Видимость',
      },
    },
    {
      name: 'tags',
      type: 'relationship',
      hasMany: true,
      relationTo: Tags.slug,
      admin: {
        position: 'sidebar',
      },
      label: {
        en: 'Tags',
        ru: 'Тэги',
      },
    },
    {
      name: 'views',
      type: 'number',
      hidden: true,
      defaultValue: 0,
      label: {
        en: 'Views',
        ru: 'Просмотры',
      },
    },
  ],
}

export default Products

@mixty1
Copy link
Author

mixty1 commented May 14, 2024

A solution has been found. I'm running the dev server using the --turbo option and maybe it's using some strict options because the UI isn't showing up with this errors, but without --turbo it's showing up normally, although I'm getting the following errors in the console:

key not found:  upload:Sizes
 ⨯ node_modules/.pnpm/@payloadcms+plugin-search@3.0.0-beta.30_@types+react@18.3.1_monaco-editor@0.38.0_next@14.3.0-_xof4nppotimeuxnbzv4dvfsslu/node_modules/@payloadcms/plugin-search/dist/Search/ui/index.js (5:30) @ LinkToDoc
 ⨯ TypeError: (0 , _payloadcms_ui_forms_Form__WEBPACK_IMPORTED_MODULE_0__.useWatchForm) is not a function
    at stringify (<anonymous>)
digest: "2857860722"
  3 | import React from 'react';
  4 | export const LinkToDoc = ()=>{
> 5 |     const form = useWatchForm();
    |                              ^
  6 |     const fields = form.fields;
  7 |     const { doc: { value: { relationTo, value: docId } } } = fields;
  8 |     const config = useConfig();

@denolfe denolfe added the v3 label May 22, 2024
@JessChowdhury JessChowdhury added the status: needs-repro If an issue does not include a reproduction label May 28, 2024
@github-actions github-actions bot removed the status: needs-triage Possible bug which hasn't been reproduced yet label May 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: needs-repro If an issue does not include a reproduction v3
Projects
None yet
Development

No branches or pull requests

5 participants