{"record":{"id":"daf43a8c86dd3457","repo":"guzzle/promises","slug":"cannot-resolve-a-rejected-promise","errorCode":null,"errorMessage":"Cannot resolve a rejected promise","messagePattern":"Cannot resolve a rejected promise","errorType":"exception","errorClass":"LogicException","httpStatus":null,"severity":"error","filePath":"src/RejectedPromise.php","lineNumber":106,"sourceCode":"    }\n\n    public function wait(bool $unwrap = true)\n    {\n        if ($unwrap) {\n            throw Create::exceptionFor($this->reason);\n        }\n\n        return null;\n    }\n\n    public function getState(): string\n    {\n        return self::REJECTED;\n    }\n\n    public function resolve($value = null): void\n    {\n        throw new \\LogicException('Cannot resolve a rejected promise');\n    }\n\n    public function reject($reason): void\n    {\n        if ($reason !== $this->reason) {\n            throw new \\LogicException('Cannot reject a rejected promise');\n        }\n    }\n\n    public function cancel(): void\n    {\n        // pass\n    }\n}\n","sourceCodeStart":88,"sourceCodeEnd":121,"githubUrl":"https://github.com/guzzle/promises/blob/42118e66a53c492effaf92bc357e931985d5c6f9/src/RejectedPromise.php#L88-L121","documentation":"RejectedPromise::resolve() always throws this LogicException: a rejected promise is settled and immutable, and the strict identity rule that lets a fulfilled promise be 'resolved' with the same value does not apply here at all. The library fails fast rather than silently ignoring a resolve() on a rejected state.","triggerScenarios":"Calling ->resolve($value) (including with the default null) on any RejectedPromise instance. No argument avoids the throw.","commonSituations":"Generic settle helpers that call resolve() unconditionally without knowing the concrete promise class; race conditions where a rejection won before a resolve path ran; reusing one promise object for multiple operations; porting code from libraries whose resolve() is a no-op on settled promises.","solutions":["Never call resolve() on a promise that may already be rejected; settle only pending promises.","Create a new Promise/FulfilledPromise when you need a fulfillment outcome.","Track settlement state in your own wrapper (or rely on then()/otherwise() to observe the outcome immutably)."],"exampleFix":"// before\n$rejected->resolve($value); // always LogicException\n// after\n$fulfilled = new \\GuzzleHttp\\Promise\\FulfilledPromise($value);","handlingStrategy":"type-guard","validationCode":"if ($p instanceof \\GuzzleHttp\\Promise\\RejectedPromise) {\n    // already rejected; resolve() would throw\n    return;\n}\n$p->resolve($value);","typeGuard":"function canResolve(\\GuzzleHttp\\Promise\\PromiseInterface $p): bool\n{\n    return !$p instanceof \\GuzzleHttp\\Promise\\RejectedPromise\n        && $p instanceof \\GuzzleHttp\\Promise\\Promise\n        && $p->getState() === 'pending';\n}","tryCatchPattern":"try {\n    $promise->resolve($value);\n} catch (\\LogicException $e) {\n    // already rejected; the rejection stands\n}","preventionTips":["Settle each promise from exactly one code path so resolve/reject never race.","Check getState() === 'pending' before resolving shared promises.","Treat settled promises as read-only: use then()/otherwise() to derive new outcomes."],"tags":["promises","state","immutability","guzzle"],"backgroundTag":"invalid-state-transition","analyzedSha":"42118e66a53c492effaf92bc357e931985d5c6f9","analyzedAt":"2026-09-14T00:10:14.865Z","contentChangedAt":"2026-09-14T00:10:14.865Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}