<table role="table">
<thead>
<tr>
<th>Q</th>
<th>A</th>
</tr>
</thead>
<tbody>
<tr>
<td>Bug report?</td>
<td>yes</td>
</tr>
<tr>
<td>Feature request?</td>
<td>no</td>
</tr>
<tr>
<td>BC Break report?</td>
<td>no</td>
</tr>
<tr>
<td>RFC?</td>
<td>no</td>
</tr>
<tr>
<td>Symfony version</td>
<td>4.0.3</td>
</tr>
</tbody>
</table>
<p dir="auto">When form is submitted, both groups "Users' and 'Strict' are validated even if there are violations in 'Users'.</p>
<p dir="auto">When put something like "123" on username and password,expected "This value is too short. It should have 6 characters or more." but "I am passwordLegal" message appears.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="class Users
{
    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata-&gt;addPropertyConstraint('username', new Assert\NotBlank());
        $metadata-&gt;addPropertyConstraint('password', new Assert\NotBlank());
        $metadata-&gt;addPropertyConstraint('username', new Assert\Length(array(
            'min' =&gt; 6,
            'max' =&gt; 12
        )));
        
        $metadata-&gt;addPropertyConstraint('password', new Assert\Length(array(
            'min' =&gt; 6
        )));
        
        $metadata-&gt;addGetterMethodConstraint('password', 'passwordLegal', new Assert\IsTrue(array(
            'message' =&gt; 'The password cannot match your username',
            'groups' =&gt; array(
                'Strict'
            )
        )));
        $metadata-&gt;setGroupSequence(array(
            'Users',
            'Strict'
        ));
    }

    public function passwordLegal()
    {
        die(&quot;I am passwordLegal&quot;);
        return $this-&gt;password !== $this-&gt;username;
    }
}"><pre class="notranslate"><code class="notranslate">class Users
{
    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata-&gt;addPropertyConstraint('username', new Assert\NotBlank());
        $metadata-&gt;addPropertyConstraint('password', new Assert\NotBlank());
        $metadata-&gt;addPropertyConstraint('username', new Assert\Length(array(
            'min' =&gt; 6,
            'max' =&gt; 12
        )));
        
        $metadata-&gt;addPropertyConstraint('password', new Assert\Length(array(
            'min' =&gt; 6
        )));
        
        $metadata-&gt;addGetterMethodConstraint('password', 'passwordLegal', new Assert\IsTrue(array(
            'message' =&gt; 'The password cannot match your username',
            'groups' =&gt; array(
                'Strict'
            )
        )));
        $metadata-&gt;setGroupSequence(array(
            'Users',
            'Strict'
        ));
    }

    public function passwordLegal()
    {
        die("I am passwordLegal");
        return $this-&gt;password !== $this-&gt;username;
    }
}
</code></pre></div>
<p dir="auto">Hello,</p>
<p dir="auto">Using the example below (smallest I could think of).</p>
<p dir="auto">If you try the given controller, you will have the following results:</p>
<ul dir="auto">
<li>test1 : all OK [as expected]</li>
<li>test2 : "is not three" [as expected]</li>
<li>test3 : <strong>_CRASH</strong>_ ""Error: Call to a member function myBar() on a non-object in /myProject/src/Me/MeBundle/Doc/Foo.php line 31"" [<strong>_NOT</strong>_ as expected]</li>
<li>test4 : "bar should not be null" [as expected]</li>
</ul>
<p dir="auto">I would expect test3 to give the same result as test4 (Meaning: If the first group of the GroupSequence is violated, the others are not executed).</p>
<p dir="auto">This is explicitly specified in the doc here : <a href="http://symfony.com/doc/current/book/validation.html#group-sequence" rel="nofollow">http://symfony.com/doc/current/book/validation.html#group-sequence</a> ""In this example, it will first validate all constraints in the group User (which is the same as the Default group). <strong>Only if all constraints in that group are valid, the second group, Strict, will be validated.</strong>"" (emphasis mine)</p>
<p dir="auto">and here: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="2639130" data-permission-text="Title is private" data-url="https://github.com/symfony/symfony/issues/2947" data-hovercard-type="issue" data-hovercard-url="/symfony/symfony/issues/2947/hovercard?comment_id=3509046&amp;comment_type=issue_comment" href="https://github.com/symfony/symfony/issues/2947#issuecomment-3509046">#2947 (comment)</a></p>
<p dir="auto">cc @bschussek</p>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&lt;?php

namespace ME\MEBundle\Doc;

use Symfony\Component\Validator\Constraints as Assert;

/**
 * @Assert\GroupSequence({&quot;FilledIn&quot;, &quot;Foo&quot;})
 */
class Foo
{
    protected $bar;

    protected $checkBar;

    public function __construct($bar, $checkBar = false)
    {
        $this-&gt;bar = $bar;
        $this-&gt;checkBar = $checkBar;
    }

    /**
     * @Assert\True(groups={&quot;Foo&quot;}, message=&quot;is not three&quot;)
     */
    public function isThree()
    {
        if ($this-&gt;checkBar &amp;&amp; null === $this-&gt;bar) {
            return new Bar(null);
        }

        return 3 == $this-&gt;getBar()-&gt;myBar();
    }

    /**
     * @Assert\NotNull(groups={&quot;FilledIn&quot;}, message=&quot;bar should not be null&quot;)
     */
    public function getBar()
    {
        return $this-&gt;bar;
    }
}"><pre class="notranslate"><span class="pl-ent">&lt;?php</span>

<span class="pl-k">namespace</span> <span class="pl-c1">ME</span>\<span class="pl-v">MEBundle</span>\<span class="pl-v">Doc</span>;

<span class="pl-k">use</span> <span class="pl-v">Symfony</span>\<span class="pl-v">Component</span>\<span class="pl-v">Validator</span>\<span class="pl-v">Constraints</span> <span class="pl-k">as</span> <span class="pl-v">Assert</span>;

<span class="pl-c">/**</span>
<span class="pl-c"> * @Assert\GroupSequence({"FilledIn", "Foo"})</span>
<span class="pl-c"> */</span>
<span class="pl-k">class</span> <span class="pl-v">Foo</span>
{
    <span class="pl-k">protected</span> <span class="pl-c1"><span class="pl-c1">$</span>bar</span>;

    <span class="pl-k">protected</span> <span class="pl-c1"><span class="pl-c1">$</span>checkBar</span>;

    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">__construct</span>(<span class="pl-s1"><span class="pl-c1">$</span>bar</span>, <span class="pl-s1"><span class="pl-c1">$</span>checkBar</span> = <span class="pl-c1">false</span>)
    {
        <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">bar</span> = <span class="pl-s1"><span class="pl-c1">$</span>bar</span>;
        <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">checkBar</span> = <span class="pl-s1"><span class="pl-c1">$</span>checkBar</span>;
    }

    <span class="pl-c">/**</span>
<span class="pl-c">     * @Assert\True(groups={"Foo"}, message="is not three")</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">isThree</span>()
    {
        <span class="pl-k">if</span> (<span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">checkBar</span> &amp;&amp; <span class="pl-c1">null</span> === <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">bar</span>) {
            <span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-v">Bar</span>(<span class="pl-c1">null</span>);
        }

        <span class="pl-k">return</span> <span class="pl-c1">3</span> == <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-en">getBar</span>()-&gt;<span class="pl-en">myBar</span>();
    }

    <span class="pl-c">/**</span>
<span class="pl-c">     * @Assert\NotNull(groups={"FilledIn"}, message="bar should not be null")</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">getBar</span>()
    {
        <span class="pl-k">return</span> <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">bar</span>;
    }
}</pre></div>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&lt;?php

namespace Me\MeBundle\Doc;

class Bar
{
    protected $bar;

    public function __construct($bar)
    {
        $this-&gt;bar = $bar;
    }

    public function myBar()
    {
        return $this-&gt;bar;
    }
}"><pre class="notranslate"><span class="pl-ent">&lt;?php</span>

<span class="pl-k">namespace</span> <span class="pl-v">Me</span>\<span class="pl-v">MeBundle</span>\<span class="pl-v">Doc</span>;

<span class="pl-k">class</span> <span class="pl-v">Bar</span>
{
    <span class="pl-k">protected</span> <span class="pl-c1"><span class="pl-c1">$</span>bar</span>;

    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">__construct</span>(<span class="pl-s1"><span class="pl-c1">$</span>bar</span>)
    {
        <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">bar</span> = <span class="pl-s1"><span class="pl-c1">$</span>bar</span>;
    }

    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">myBar</span>()
    {
        <span class="pl-k">return</span> <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">bar</span>;
    }
}</pre></div>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&lt;?php

namespace Me\MeBundle\Controller;

use Me\MeBundle\Doc;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

use Symfony\Component\HttpFoundation\JsonResponse;

class DefaultController extends Controller
{
    protected function getFooData(Foo $foo)
    {
        $json = [['bar' =&gt; null === $foo-&gt;getBar() ? null : (array)$foo-&gt;getBar()]];

        $violations = $this-&gt;get('validator')-&gt;validate($foo);

        $errors = [];

        foreach($violations as $violation) {
            $errors[] = $violation-&gt;getMessage();
        }

        $json[] = $errors;

        return $json;
    }

    /**
     * @Route(&quot;/test1&quot;, defaults={&quot;_format&quot;=&quot;json&quot;})
     */
    public function test1Action()
    {
        new Foo(null);

        $foo = new Foo(new Bar(3));

        return new JsonResponse($this-&gt;getFooData($foo));
    }

    /**
     * @Route(&quot;/test2&quot;, defaults={&quot;_format&quot;=&quot;json&quot;})
     */
    public function test2Action()
    {
        $foo = new Foo(new Bar(4));

        return new JsonResponse($this-&gt;getFooData($foo));
    }

    /**
     * @Route(&quot;/test3&quot;, defaults={&quot;_format&quot;=&quot;json&quot;})
     */
    public function test3Action()
    {
        $foo = new Foo(null);

        return new JsonResponse($this-&gt;getFooData($foo));
    }

    /**
     * @Route(&quot;/test4&quot;, defaults={&quot;_format&quot;=&quot;json&quot;})
     */
    public function test4Action()
    {
        $foo = new Foo(null, true);

        return new JsonResponse($this-&gt;getFooData($foo));
    }
}"><pre class="notranslate"><span class="pl-ent">&lt;?php</span>

<span class="pl-k">namespace</span> <span class="pl-v">Me</span>\<span class="pl-v">MeBundle</span>\<span class="pl-v">Controller</span>;

<span class="pl-k">use</span> <span class="pl-v">Me</span>\<span class="pl-v">MeBundle</span>\<span class="pl-v">Doc</span>;

<span class="pl-k">use</span> <span class="pl-v">Symfony</span>\<span class="pl-v">Bundle</span>\<span class="pl-v">FrameworkBundle</span>\<span class="pl-v">Controller</span>\<span class="pl-v">Controller</span>;

<span class="pl-k">use</span> <span class="pl-v">Sensio</span>\<span class="pl-v">Bundle</span>\<span class="pl-v">FrameworkExtraBundle</span>\<span class="pl-v">Configuration</span>\<span class="pl-v">Route</span>;
<span class="pl-k">use</span> <span class="pl-v">Sensio</span>\<span class="pl-v">Bundle</span>\<span class="pl-v">FrameworkExtraBundle</span>\<span class="pl-v">Configuration</span>\<span class="pl-v">Template</span>;

<span class="pl-k">use</span> <span class="pl-v">Symfony</span>\<span class="pl-v">Component</span>\<span class="pl-v">HttpFoundation</span>\<span class="pl-v">JsonResponse</span>;

<span class="pl-k">class</span> <span class="pl-v">DefaultController</span> <span class="pl-k">extends</span> <span class="pl-v">Controller</span>
{
    <span class="pl-k">protected</span> <span class="pl-k">function</span> <span class="pl-en">getFooData</span>(<span class="pl-smi"><span class="pl-smi">Foo</span></span> <span class="pl-s1"><span class="pl-c1">$</span>foo</span>)
    {
        <span class="pl-s1"><span class="pl-c1">$</span>json</span> = [[<span class="pl-s">'bar'</span> =&gt; <span class="pl-c1">null</span> === <span class="pl-s1"><span class="pl-c1">$</span>foo</span>-&gt;<span class="pl-en">getBar</span>() ? <span class="pl-c1">null</span> : (<span class="pl-smi">array</span>)<span class="pl-s1"><span class="pl-c1">$</span>foo</span>-&gt;<span class="pl-en">getBar</span>()]];

        <span class="pl-s1"><span class="pl-c1">$</span>violations</span> = <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-en">get</span>(<span class="pl-s">'validator'</span>)-&gt;<span class="pl-en">validate</span>(<span class="pl-s1"><span class="pl-c1">$</span>foo</span>);

        <span class="pl-s1"><span class="pl-c1">$</span>errors</span> = [];

        <span class="pl-k">foreach</span>(<span class="pl-s1"><span class="pl-c1">$</span>violations</span> <span class="pl-k">as</span> <span class="pl-s1"><span class="pl-c1">$</span>violation</span>) {
            <span class="pl-s1"><span class="pl-c1">$</span>errors</span>[] = <span class="pl-s1"><span class="pl-c1">$</span>violation</span>-&gt;<span class="pl-en">getMessage</span>();
        }

        <span class="pl-s1"><span class="pl-c1">$</span>json</span>[] = <span class="pl-s1"><span class="pl-c1">$</span>errors</span>;

        <span class="pl-k">return</span> <span class="pl-s1"><span class="pl-c1">$</span>json</span>;
    }

    <span class="pl-c">/**</span>
<span class="pl-c">     * @Route("/test1", defaults={"_format"="json"})</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">test1Action</span>()
    {
        <span class="pl-k">new</span> <span class="pl-v">Foo</span>(<span class="pl-c1">null</span>);

        <span class="pl-s1"><span class="pl-c1">$</span>foo</span> = <span class="pl-k">new</span> <span class="pl-v">Foo</span>(<span class="pl-k">new</span> <span class="pl-v">Bar</span>(<span class="pl-c1">3</span>));

        <span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-v">JsonResponse</span>(<span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-en">getFooData</span>(<span class="pl-s1"><span class="pl-c1">$</span>foo</span>));
    }

    <span class="pl-c">/**</span>
<span class="pl-c">     * @Route("/test2", defaults={"_format"="json"})</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">test2Action</span>()
    {
        <span class="pl-s1"><span class="pl-c1">$</span>foo</span> = <span class="pl-k">new</span> <span class="pl-v">Foo</span>(<span class="pl-k">new</span> <span class="pl-v">Bar</span>(<span class="pl-c1">4</span>));

        <span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-v">JsonResponse</span>(<span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-en">getFooData</span>(<span class="pl-s1"><span class="pl-c1">$</span>foo</span>));
    }

    <span class="pl-c">/**</span>
<span class="pl-c">     * @Route("/test3", defaults={"_format"="json"})</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">test3Action</span>()
    {
        <span class="pl-s1"><span class="pl-c1">$</span>foo</span> = <span class="pl-k">new</span> <span class="pl-v">Foo</span>(<span class="pl-c1">null</span>);

        <span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-v">JsonResponse</span>(<span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-en">getFooData</span>(<span class="pl-s1"><span class="pl-c1">$</span>foo</span>));
    }

    <span class="pl-c">/**</span>
<span class="pl-c">     * @Route("/test4", defaults={"_format"="json"})</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">test4Action</span>()
    {
        <span class="pl-s1"><span class="pl-c1">$</span>foo</span> = <span class="pl-k">new</span> <span class="pl-v">Foo</span>(<span class="pl-c1">null</span>, <span class="pl-c1">true</span>);

        <span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-v">JsonResponse</span>(<span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-en">getFooData</span>(<span class="pl-s1"><span class="pl-c1">$</span>foo</span>));
    }
}</pre></div>