About bitrix-result-and-errors
A Bitrix development skill for consistent result and error handling. It explains when to return Result objects or raise exceptions, along with error codes, ORM results, and controller boundaries.
Key features
- 01Rules for Result versus exceptions
- 02Stable machine-readable error codes
- 03Typed result patterns
- 04ORM result handling guidance
- 05Controller error response patterns
- 06Exception handling at module boundaries
Use cases
- 01Designing service method contracts
- 02Returning validation and business errors
- 03Handling failed ORM operations
- 04Mapping exceptions to controller errors
Install
Copy the command and run it in a terminal.
$
npx skills add https:/ / github.com/ bxmaximum/ bitrix-framework-skills --skill bitrix-result-and-errorsAfter installing, type/bitrix-result-and-errorsin Claude Code to confirm it loaded.
Details
From the project READMEResult and Error
Baseline: main 23.0+ · Verified: main 26.800.0
Contract
- Expected failures (validation, business rule, not found, no rights) →
ResultwithErrors. - Broken state or contract (module missing, DB down, misconfiguration, bug) → exception.
- One method, one contract: always a
Result, or a value plus exceptions for the exceptional case. Neverbool/null/-1/['error' => …].
Bitrix\Main\Result
use Bitrix\Main\Error;
use Bitrix\Main\Result;
$result = new Result();
if ($title === '')
{
return $result->addError(new Error('Title required', 'BLOG_POST_TITLE_EMPTY', ['field' => 'title']));
}
return $result->setData(['id' => $id]);
isSuccess(),addError(Error),addErrors(Error[]),getErrors(),getError()(first ornull),getErrorMessages(),getErrorCollection(),setData(array),getData(). Setters return$this.setData()silently dropsSqlExpressionvalues.
Error and codes
new Error($message, $code = 0, $customData = null). JSON form: {"message", "code", "customData"}.
- Codes are stable and machine-readable: module + entity + reason (
BLOG_POST_NOT_FOUND), kept in constants. Clients branch on the code, not the text. - Messages via
Loc::getMessage('BLOG_ERROR_POST_TITLE_EMPTY'). ErrorCollection:new ErrorCollection([$error]),setError(),add([...]),getErrorByCode('CODE'), iterable,isEmpty(),toArray().
Typed result
Give callers getters instead of getData()['post']:
final class CreatePostResult extends \Bitrix\Main\Result
{
private ?Post $post = null;
public function setPost(Post $post): self
{
$this->post = $post;
return $this;
}
public function getPost(): ?Post
{
return $this->post;
}
}
ORM results (Bitrix\Main\ORM\Data\*)
AddResult:getId(),getPrimary(),getObject().UpdateResult:getId(),getPrimary(),getAffectedRowsCount().DeleteResult: no methods of its own (no affected-rows count).Bitrix\Main\Entity\*Resultare compat aliases. WriteORM\Data\*.- A failed ORM result whose errors nobody read (
isSuccess()/getErrors()) raisesE_USER_WARNINGon destruct. Always check it and return it, or copy its errors up.
$add = PostTable::add(['TITLE' => $title]);
if (!$add->isSuccess())
{
return (new Result())->addErrors($add->getErrors());
}
$id = $add->getId();
Other result types
EventResult(SUCCESS,ERROR,UNDEFINED) is a handler's answer, not a service result:bitrix-events.ValidationResult(bitrix-validation) extendsResult: add its errors to the service result.
Controllers
$this->addErrors($result->getErrors()); return null; gives {"status":"error","data":null,"errors":[…]}. Envelope details: bitrix-controllers.
Exceptions at the boundary
Catch at the module/controller edge, log, return a generic error:
try
{
return $this->service->run($dto);
}
catch (\Bitrix\Main\SystemException $e)
{
$this->logger->error('Run failed', ['exception' => $e]);
return (new Result())->addError(new Error('Internal error', 'VENDOR_INTERNAL_ERROR'));
}
- Never swallow
\Throwablewithout logging. - Developer mistakes (
InvalidArgumentException,LogicException,TypeError) and "can't happen" domain states (division by zero in a money type) stay exceptions.
Comments
Markdown supported