An entity field with the machine name "links" causes JSON:API validation to fail

Created on 27 March 2023, about 1 year ago
Updated 15 February 2024, 4 months ago

Problem/Motivation

If I have a field on a bundle called "links" then json:api validation fails. This causes very cryptic error messages if you have assertion exceptions turned on and is incredibly hard to debug

The error message is something like
AssertionError: A JSON:API response failed validation (see the logs for details). Please report this in the issue queue on drupal.org in assert()

Debugging into the schema validation is very difficult as it's recursive and the schema expects a bunch of keys underneath the links keyword. This leads to validation errors about missing data, meta, etc keys which just adds to the confusion.

Steps to reproduce

  1. Ensure assertion exceptions are turned on (zend.assertions and assert.exception should be on in PHP INI)
  2. Install standard profile and enable jsonapi module
  3. Add a field to a content type with the machine name "links" (no field_ prefix)
  4. Create a piece of content, filling in just the title
  5. Visit the jsonapi endpoint for that content, e.g /jsonapi/node/article/UUID
  6. Notice the 500
  7. Delete the links field
  8. Revisit the jsonapi endpoint
  9. Notice the 200

Proposed resolution

Not a clue

🐛 Bug report
Status

Needs work

Version

11.0 🔥

Component
JSON API 

Last updated 2 days ago

Created by

🇦🇺Australia acbramley

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • Issue created by @acbramley
  • Status changed to Needs review about 1 year ago
  • 🇦🇺Australia acbramley

    Failing test to show the issue.

  • Status changed to Needs work about 1 year ago
  • 🇳🇱Netherlands bbrala Netherlands

    Thanks for reporting this issue. Is there any chance we can get a full stacktrace of the issue? That would help understand the issue better without running it locally.

  • 🇦🇺Australia acbramley

    @bbrala here's the full stack trace in the JSON:API response

    AssertionError: A JSON:API response failed validation (see the logs for details). Please report this in the issue queue on drupal.org in /data/app/core/modules/jsonapi/src/EventSubscriber/ResourceResponseValidator.php:117
    Stack trace:
    #0 /data/app/core/modules/jsonapi/src/EventSubscriber/ResourceResponseValidator.php(117): assert()
    #1 /data/app/core/modules/jsonapi/src/EventSubscriber/ResourceResponseValidator.php(108): Drupal\\jsonapi\\EventSubscriber\\ResourceResponseValidator->doValidateResponse()
    #2 [internal function]: Drupal\\jsonapi\\EventSubscriber\\ResourceResponseValidator->onResponse()
    #3 /data/app/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func()
    #4 /data/vendor/symfony/http-kernel/HttpKernel.php(196): Drupal\\Component\\EventDispatcher\\ContainerAwareEventDispatcher->dispatch()
    #5 /data/vendor/symfony/http-kernel/HttpKernel.php(184): Symfony\\Component\\HttpKernel\\HttpKernel->filterResponse()
    #6 /data/vendor/symfony/http-kernel/HttpKernel.php(74): Symfony\\Component\\HttpKernel\\HttpKernel->handleRaw()
    #7 /data/app/core/lib/Drupal/Core/StackMiddleware/Session.php(58): Symfony\\Component\\HttpKernel\\HttpKernel->handle()
    #8 /data/app/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\\Core\\StackMiddleware\\Session->handle()
    #9 /data/vendor/asm89/stack-cors/src/Cors.php(53): Drupal\\Core\\StackMiddleware\\KernelPreHandle->handle()
    #10 /data/app/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Asm89\\Stack\\Cors->handle()
    #11 /data/app/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\\Core\\StackMiddleware\\ReverseProxyMiddleware->handle()
    #12 /data/app/core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php(51): Drupal\\Core\\StackMiddleware\
    egotiationMiddleware->handle()
    #13 /data/app/core/lib/Drupal/Core/DrupalKernel.php(686): Drupal\\Core\\StackMiddleware\\StackedHttpKernel->handle()
    #14 /data/app/index.php(19): Drupal\\Core\\DrupalKernel->handle()
    #15 {main}
    
    Next Symfony\\Component\\HttpKernel\\Exception\\HttpException: A JSON:API response failed validation (see the logs for details). Please report this in the issue queue on drupal.org in /data/app/core/modules/jsonapi/src/EventSubscriber/DefaultExceptionSubscriber.php:49
    Stack trace:
    #0 [internal function]: Drupal\\jsonapi\\EventSubscriber\\DefaultExceptionSubscriber->onException()
    #1 /data/app/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func()
    #2 /data/vendor/symfony/http-kernel/HttpKernel.php(221): Drupal\\Component\\EventDispatcher\\ContainerAwareEventDispatcher->dispatch()
    #3 /data/vendor/symfony/http-kernel/HttpKernel.php(89): Symfony\\Component\\HttpKernel\\HttpKernel->handleThrowable()
    #4 /data/app/core/lib/Drupal/Core/StackMiddleware/Session.php(58): Symfony\\Component\\HttpKernel\\HttpKernel->handle()
    #5 /data/app/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\\Core\\StackMiddleware\\Session->handle()
    #6 /data/vendor/asm89/stack-cors/src/Cors.php(53): Drupal\\Core\\StackMiddleware\\KernelPreHandle->handle()
    #7 /data/app/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Asm89\\Stack\\Cors->handle()
    #8 /data/app/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\\Core\\StackMiddleware\\ReverseProxyMiddleware->handle()
    #9 /data/app/core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php(51): Drupal\\Core\\StackMiddleware\
    egotiationMiddleware->handle()
    #10 /data/app/core/lib/Drupal/Core/DrupalKernel.php(686): Drupal\\Core\\StackMiddleware\\StackedHttpKernel->handle()
    #11 /data/app/index.php(19): Drupal\\Core\\DrupalKernel->handle()
    #12 {main}
    
  • 🇮🇳India sijumpk

    The keyword "links" is considered as a json response property just like "meta". Because of that when the string is validated against the JSON Schema (jsonapi/schema.json), its getting failed. In a normal scenario (in D10+), we can't add a node field without "field_" prefix. So this won't be a problem unless we create node fields problematically.

  • 🇦🇺Australia acbramley

    we can't add a node field without "field_" prefix

    Yes we can, if the field_ui prefix setting is emptied which is actually quite common.

  • Pipeline finished with Failed
    4 months ago
    Total: 171s
    #95494
  • Pipeline finished with Success
    4 months ago
    #95523
  • Pipeline finished with Success
    4 months ago
    Total: 469s
    #95549
  • Pipeline finished with Success
    4 months ago
    Total: 4671s
    #95499
  • Pipeline finished with Success
    4 months ago
    Total: 592s
    #95565
  • Pipeline finished with Success
    4 months ago
    Total: 980s
    #95686
  • Pipeline finished with Success
    4 months ago
    Total: 471s
    #95706
  • 🇮🇳India sijumpk

    In that case we can avoid this problem by removing "links" from patternProperties regex of "attributes" definition (jsonapi/schema.json > definitions > attributes > patternProperties). Thats the place this error is getting triggered. In case of "relationships" definition, just "id" and "type" are blacklisted in its regex (patternProperties).

    In order to avoid changes to patternProperties, we can declare "links" as a field using hook_entity_base_field_info. By doing so we can make "links" a reserved one and could avoid making a field with that name. But the problem is that we can't do it in jsonapi.module. If we do so, someone can create the field by temporarily disabling jsonapi module.

    The test case you provided is added to the current MR. Unfortunately the test case is not getting failed on running pipeline. I could generate the failing case in my local. Here is the passing pipeline details.

    https://git.drupalcode.org/issue/drupal-3350525/-/jobs/824500

    The status code (200) and response are printed in it. Any idea why its getting passed in the server only?

  • 🇮🇳India sijumpk

    sijumpk changed the visibility of the branch 3388358-setprefix-when-the to hidden.

Production build 0.69.0 2024