Fixing Next.js Server Action error: Only plain objects can be passed to Server Actions

Problem

I wanted to create a workflow but encountered an error at the submission of form.

Error: Only plain objects, and a few built-ins, can be passed to Server Actions. Classes or null prototypes are not supported.

How can I solve the error? I’m stuck in it now and need your help. Thanks in advance! The screenshot is as below:

Code

app/(dashboard)/workflows/_components/CreateWorkflowDialog.tsx:

'use client';

import React, { useCallback, useState } from 'react';
import {useForm} from 'react-hook-form';
import {zodResolver} from '@hookform/resolvers/zod';
import {useMutation} from '@tanstack/react-query';
import {toast} from 'sonner';
import {Layers2Icon, Loader2} from 'lucide-react';
import { createWorkflowSchema, createWorkflowSchemaType } from '@/schema/workflow';
import { CreateWorkflow } from '@/actions/workflows/createWorkflow';
import { myLog } from '@/lib/utils';
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel } from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import { Button } from '@/components/ui/button';

function CreateWorkflowDialog({triggerText}: {triggerText?: string}) {
  const form = useForm<createWorkflowSchemaType>({
    resolver: zodResolver(createWorkflowSchema),
    defaultValues: {
      name: '',
      // description: '',
    },
  });

  const {mutate, isPending} = useMutation({
    mutationFn: CreateWorkflow,
    onSuccess: () => {
      toast.success('Workflow created', {id: 'create-workflow'});
    },
    onError: (err) => {
      myLog('err onError', err);
      toast.error('Failed to create workflow', {id: 'create-workflow'});
    },
  });

  const onSubmit = useCallback((values: createWorkflowSchemaType) => {
    toast.loading('Creating workflow...', {id: 'create-workflow'});
    myLog('values onSubmit', values);
    mutate(values);
  }, [mutate]);

  return (
    ......
    <Form {...form}>
            <form className="w-full space-y-8" onSubmit={form.handleSubmit(onSubmit)}>
              <FormField 
                control={form.control}
                name="name"
                render={({field}) => {
                  myLog('field name', field);

                  return (
                    <FormItem>
                      <FormLabel className="flex items-center gap-1">
                        Name
                        <p className="text-xs text-primary">(required)</p>
                      </FormLabel>
                      <FormControl>
                        <Input {...field} />
                      </FormControl>
                      <FormDescription>Choose a descriptive and unique name</FormDescription>
                    </FormItem>
                  );
                }}
              />

              <FormField 
                control={form.control}
                name="description"
                render={({field}) => (
                  <FormItem>
                    <FormLabel className="flex items-center gap-1">
                      Description
                      <p className="text-xs text-muted-foreground">(optional)</p>
                    </FormLabel>
                    <FormControl>
                      <Textarea className='resize-none' {...field} />
                    </FormControl>
                    <FormDescription>
                      Provide a brief description of whate your workflow does.
                      <br />
                      This is optional but can help you remember the workflow&apos;s purpose
                    </FormDescription>
                  </FormItem>
                )}
              />
              <Button type='submit' className='w-full' disabled={isPending}>
                {!isPending && 'Proceed'}
                {isPending && <Loader2 className="animate-spin" />}
              </Button>
            </form>
          </Form>
    ......
  );
}

export default CreateWorkflowDialog

schema/workflow.ts:

import {z} from 'zod';

export const createWorkflowSchema = z.object({
  name: z.string().max(50),
  description: z.string().max(80).optional(),
});

export type createWorkflowSchemaType = z.infer<typeof createWorkflowSchema>;

actions/workflows/createWorkflow.ts:

'use server'

import { createWorkflowSchema, createWorkflowSchemaType } from '@/schema/workflow';

export async function CreateWorkflow(form: createWorkflowSchemaType) {
  const {success, data} = createWorkflowSchema.safeParse(form);
  ......
}

Environment

  • next: 14.2.5
  • react: ^18
  • react-hook-form: ^7.71.1
  • zod: ^4.3.5
  • @tanstack/react-query: ^5.90.20
  • sonner: ^2.0.7
  • lucide-react: ^0.562.0