{"record":{"id":"4d5d5963e48fd294","repo":"abpframework/abp","slug":"predicate-cannot-be-started-again","errorCode":null,"errorMessage":"Predicate cannot be started again.","messagePattern":"Predicate cannot be started again\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"framework/src/Volo.Abp.Core/System/Linq/PredicateOperator.cs","lineNumber":148,"sourceCode":"\n    private Expression<Func<T, bool>>? _predicate;\n\n    /// <summary>Determines if the predicate is started.</summary>\n    public bool IsStarted => _predicate != null;\n\n    /// <summary> A default expression to use only when the expression is null </summary>\n    public bool UseDefaultExpression => DefaultExpression != null;\n\n    /// <summary>The default expression</summary>\n    public Expression<Func<T, bool>>? DefaultExpression { get; set; }\n\n    /// <summary>Set the Expression predicate</summary>\n    /// <param name=\"exp\">The first expression</param>\n    public Expression<Func<T, bool>> Start(Expression<Func<T, bool>> exp)\n    {\n        if (IsStarted)\n        {\n            throw new Exception(\"Predicate cannot be started again.\");\n        }\n\n        return _predicate = exp;\n    }\n\n    /// <summary>Or</summary>\n    public Expression<Func<T, bool>> Or([NotNull] Expression<Func<T, bool>> expr2)\n    {\n        return (IsStarted) ? _predicate = Predicate.Or(expr2) : Start(expr2);\n    }\n\n    /// <summary>And</summary>\n    public Expression<Func<T, bool>> And([NotNull] Expression<Func<T, bool>> expr2)\n    {\n        return (IsStarted) ? _predicate = Predicate.And(expr2) : Start(expr2);\n    }\n\n    /// <summary> Show predicate string </summary>","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/abpframework/abp/blob/7ed43b1931b9df46a50c0c59148a18645641d0df/framework/src/Volo.Abp.Core/System/Linq/PredicateOperator.cs#L130-L166","documentation":"ExpressionStarter<T>.Start(exp) seeds the predicate builder with a first expression and may be called only once; the builder tracks 'started' state via the private _predicate field (IsStarted == _predicate != null). The Or() and And() methods auto-call Start() internally when the builder is not yet started, then combine, so explicit Start() calls are rarely needed. Calling Start() after the predicate is already seeded (directly, or transitively via Or/And) is treated as a logic error and aborted rather than silently overwriting the predicate.","triggerScenarios":"Calling ExpressionStarter<T>.Start(expr) when IsStarted is already true: after a prior Start(), or after Or()/And() which set _predicate internally on the first combine.","commonSituations":"Building a dynamic LINQ filter in a loop where Start() is called per iteration instead of Or()/And(); sharing one ExpressionStarter instance across two builder methods that each call Start(); porting code that treats Start like an assignment.","solutions":["Replace the second Start(expr) with Or(expr) or And(expr) - they auto-start when needed and combine thereafter.","If a fresh seed is required, create a new ExpressionStarter<T> via PredicateBuilder.New<T>() instead of reusing one.","Guard the call: 'if (!predicate.IsStarted) predicate.Start(seed);' before chaining Or/And."],"exampleFix":"// before\nvar pred = PredicateBuilder.New<MyEntity>();\npred.Start(x => x.Active);\npred.Start(x => x.Name == \"foo\"); // throws\n\n// after\nvar pred = PredicateBuilder.New<MyEntity>();\npred.Start(x => x.Active);\npred.And(x => x.Name == \"foo\");","handlingStrategy":"validation","validationCode":"var pred = PredicateBuilder.New<MyEntity>();\n// never call Start twice; use Or/And which auto-start\nif (someCondition) pred = pred.Or(x => x.Active);  // safe first call\nelse pred = pred.Or(x => x.Inactive);","typeGuard":"bool CanStart<T>(ExpressionStarter<T> p) => !p.IsStarted;","tryCatchPattern":null,"preventionTips":["Treat Start() as a one-time seed; prefer Or()/And() for all subsequent appends.","Create a fresh ExpressionStarter via PredicateBuilder.New<T>() for each independent predicate rather than reusing and resetting.","In loops, accumulate with Or/And against a single starter instead of calling Start per iteration."],"tags":["linq","predicate-builder","expression","logic-error"],"backgroundTag":null,"analyzedSha":"7ed43b1931b9df46a50c0c59148a18645641d0df","analyzedAt":"2026-08-13T16:26:11.351Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}