Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

WVA's avatar
Level 7

Spatie Laravel data, cast date

I'm trying to use the Spatie Laravel Data package to cast a date, however I'm facing following error:

App\Data\ExpenseData::__construct(): Argument #2 ($expense_date) must be of type App\Data\Carbon, string given, called in {mypath}/vendor/spatie/laravel-data/src/Resolvers/DataFromArrayResolver.php on line 79

The date that I'm passing is a string formatted in Y-m-d. From what I understand of the docs it should then automatically be casted to a Carbon object. Not sure what's going wrong. Any tips?

My Data object:

<?php

namespace App\Data;

use Spatie\LaravelData\Data;
use Spatie\LaravelData\WithCast;
use Spatie\LaravelData\Casts\DateTimeInterfaceCast;

class ExpenseData extends Data
{
    public function __construct(
        public string|Optional $invoice_id,
        #[WithCast(DateTimeInterfaceCast::class)]
        public Carbon $expense_date,
        public string $description,
        public string $vendor,
        public string|Optional $vat_number,
        public int $gross_amount,
        public int $vat_amount,
        public int $net_amount,
        public string|Optional $currency,
        public string|Optional $note,
    ) {}
}
0 likes
5 replies
LaryAI's avatar
Level 58

The error message suggests that the $expense_date argument in the ExpenseData constructor should be of type App\Data\Carbon, but a string is being passed instead.

To fix this issue, you need to make sure that the $expense_date argument is an instance of the Carbon class.

Here's how you can modify your code to resolve the error:

use Carbon\Carbon;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\WithCast;
use Spatie\LaravelData\Casts\DateTimeInterfaceCast;

class ExpenseData extends Data
{
    public function __construct(
        public string|Optional $invoice_id,
        #[WithCast(DateTimeInterfaceCast::class)]
        public Carbon|string $expense_date,
        public string $description,
        public string $vendor,
        public string|Optional $vat_number,
        public int $gross_amount,
        public int $vat_amount,
        public int $net_amount,
        public string|Optional $currency,
        public string|Optional $note,
    ) {
        if (is_string($expense_date)) {
            $expense_date = Carbon::parse($expense_date);
        }
        
        $this->expense_date = $expense_date;
    }
}

In the modified code, we added a type hint Carbon|string to the $expense_date property to indicate that it can accept either a Carbon instance or a string. Inside the constructor, we check if the provided value is a string, and if so, we parse it into a Carbon instance using Carbon::parse(). Finally, we assign the parsed Carbon instance back to the $expense_date property.

This should resolve the error and allow you to use the Spatie Laravel Data package to cast the date correctly.

DhPandya's avatar

@wva In your ExpenseData class constructor you've cast the $expense_date as Carbon object. So from the function you're passing it you must pass the Carbon object instead passing a simple string date.

WVA's avatar
Level 7

@dhpandya : that is not how I understand it from the docs:

https://spatie.be/docs/laravel-data/v3/as-a-data-transfer-object/casts

Local casts Local casts are defined within the data object itself and can be added using attributes:

class SongData extends Data
{
    public function __construct(
        public string $title,
        public string $artist,
        #[WithCast(DateTimeInterfaceCast::class)]
        public DateTime $date,
        #[WithCast(EnumCast::class)]
        public Format $format,
    ) {
    }
}  

Now it is possible to create a data object like this without exceptions:

SongData::from([
    'title' => 'Never gonna give you up',
    'artist' => 'Rick Astley',
    'date' => '27-07-1987',
    'format' => 'vinyl',
]);	
WVA's avatar
Level 7

Found already one error, had to import use Spatie\LaravelData\Attributes\WithCast;

Still getting

App\Data\ExpenseData::__construct(): Argument #2 ($expense_date) must be of type App\Data\Carbon, Spatie\LaravelData\Casts\Uncastable given, called in {my path}/vendor/spatie/laravel-data/src/Resolvers/DataFromArrayResolver.php on line 79
WVA's avatar
WVA
OP
Best Answer
Level 7

Managed to fix it by passing the date format

#[WithCast(DateTimeInterfaceCast::class, format: 'Y-m-d')]
2 likes

Please or to participate in this conversation.