Skip to content

API: Cannot set master_picture_attachment via PATCH - isPicture() validation fails on deserialization #1370

@WangChuDi

Description

@WangChuDi

Description

When using the REST API to set master_picture_attachment on a Part via PATCH, the request always fails with:

"The preview attachment must be a valid picture!"

This happens even when the referenced attachment:

  • Has picture: true in its serialized response
  • Has a valid image URL ending in .jpg
  • Was successfully created via POST /api/attachments with an external image URL

Steps to Reproduce

  1. Create a part via API:
curl -X POST /api/parts -d '{"name": "Test", "category": "/api/categories/1"}'
# Returns part id=5
  1. Create an image attachment for the part:
curl -X POST /api/attachments -d '{
  "name": "Product Image",
  "attachment_type": "/api/attachment_types/1",
  "url": "https://assets.lcsc.com/images/lcsc/900x900/20221228_Example_C17414_front.jpg",
  "element": "/api/parts/5"
}'
# Returns attachment id=14, "picture": true
  1. Try to set it as master picture:
curl -X PATCH /api/parts/5 \
  -H "Content-Type: application/merge-patch+json" \
  -d '{"master_picture_attachment": {"@id": "/api/attachments/14", "_type": "Part"}}'
  1. Response: 422 - "The preview attachment must be a valid picture!"

Expected Behavior

Since the attachment already exists, has picture: true, and contains a valid image URL (.jpg), setting it as master_picture_attachment should succeed.

Actual Behavior

The Assert\Expression('value == null or value.isPicture()') validation on master_picture_attachment fails.

Root Cause Analysis

The issue appears to be in how API Platform deserializes the @id reference. When processing the PATCH request, it seems to create/load an Attachment object where isPicture() cannot properly evaluate because:

  • The external_path may not be populated on the deserialized object
  • isPicture() checks hasExternal() then parses the URL extension, but during deserialization the path data may not be available

The validation at src/Entity/Parts/Part.php:164:

#[Assert\Expression('value == null or value.isPicture()', message: 'part.master_attachment.must_be_picture')]
protected ?Attachment $master_picture_attachment = null;

calls isPicture() which relies on getExternalPath() returning the URL - but this may be null during the deserialization/validation phase.

Workaround

Currently the only way to set master_picture_attachment is through the Web UI or direct database access (UPDATE parts SET id_preview_attachment=X WHERE id=Y).

Environment

  • Part-DB version: latest (Docker image jbtronics/part-db1:latest)
  • PHP 8.x, Symfony, API Platform
  • Using SQLite database

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions