-
-
Notifications
You must be signed in to change notification settings - Fork 468
Description
Description
Native PHP enums (available since PHP 8.1) are serialized as opaque Object <ClassName> strings in Sentry error reports, losing their value entirely. For example, a BackedEnum like:
enum AttributeSource: string {
case AKENEO = 'akeneo';
case NETSUITE = 'netsuite';
}Shows up as Object iFixit\Admin\Akeneo\AttributeSource in stack trace variable dumps — with no indication of which case was active.
Root Cause
AbstractSerializer::serializeRecursively() treats enums as generic objects. Since native enums don't implement SerializableInterface, they fall through to serializeValue(), which outputs 'Object ' . $reflection->getName(). Enums also lack a public id property or getId() method, so they don't even get the (#id) suffix.
sentry-php/src/Serializer/AbstractSerializer.php
Lines 119 to 147 in d94ee1b
| if (\is_object($value)) { | |
| $classSerializers = $this->resolveClassSerializers($value); | |
| // Try each serializer until there is none left or the serializer returned data | |
| foreach ($classSerializers as $classSerializer) { | |
| try { | |
| $serializedObjectData = $classSerializer($value); | |
| if (\is_array($serializedObjectData)) { | |
| return [ | |
| 'class' => \get_class($value), | |
| 'data' => $this->serializeRecursively($serializedObjectData, $_depth + 1), | |
| ]; | |
| } | |
| } catch (\Throwable $e) { | |
| // Ignore any exceptions generated by a class serializer | |
| } | |
| } | |
| if ($value instanceof \DateTimeInterface) { | |
| return $this->formatDate($value); | |
| } | |
| if ($this->serializeAllObjects || ($value instanceof \stdClass)) { | |
| return $this->serializeObject($value, $_depth); | |
| } | |
| } | |
| return $this->serializeValue($value); |
Suggested Fix
Add a check for UnitEnum in serializeRecursively(), before the generic object handling:
if ($value instanceof \UnitEnum) {
return $value instanceof \BackedEnum
? $value->value
: $value->name;
}Or alternatively in serializeValue():
if ($value instanceof \UnitEnum) {
$enumValue = $value instanceof \BackedEnum ? $value->value : $value->name;
return $reflection->getName() . '::' . $value->name . '(' . $enumValue . ')';
}Workaround
We're currently working around this by having our enums implement SerializableInterface:
enum AttributeSource: string implements SerializableInterface {
case AKENEO = 'akeneo';
case NETSUITE = 'netsuite';
public function toSentry(): array {
return [$this->value];
}
}This works but requires touching every enum individually.
Environment
sentry/sentry: ^4.10.0- PHP: 8.4
Metadata
Metadata
Assignees
Fields
Give feedbackProjects
Status