feat(domain): introduce error slugs (#12030)

# Which Problems Are Solved

As part of https://github.com/zitadel/zitadel/issues/11917 we want to
introduce error slugs so (API) clients can rely on stable,
machine-readable errors and act accordingly.

# How the Problems Are Solved

- Added a `NewSlug` helper function in the domain package.
- Added `ErrorDetails` to the `ZitadelError`
- Added an `zitadel.error.v2.ErrorDetail` proto message
- Updated the connectRPC error interceptor to map new slug based errors
to the new `ErrorDetail`
- Defined some common slugs and error functions like internal errors
- Defined (session) specific slugs used in the `DeleteSession` and
`CheckUser` functions and replaced old implementations
- Updated integration tests to check specific errors if the relation
database feature is enabled
- Updated doc and guideline to reflect the latest changes and decisions
- Updated DeleteSession endpoint API to list possible slugs

# Additional Changes

None

# Additional Context

- closes #11957

---------

Co-authored-by: Wim Van Laer <[email protected]>
This commit is contained in:
Livio Spring
2026-04-13 09:47:04 +02:00
committed by GitHub
co-authored by Wim Van Laer
parent 5c9361f6c7
commit a2bf528ca0
18 changed files with 524 additions and 97 deletions
+29
View File
@@ -0,0 +1,29 @@
syntax = "proto3";
package zitadel.error.v2;
import "google/protobuf/struct.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/error/v2;errorpb";
// ErrorDetail is the ZITADEL standard for rich error responses.
message ErrorDetail {
// The slug is a stable, machine-readable, two-part identifier (e.g., "user.already_exists").
// It is intended for programmatic use and does not change across versions, making it suitable for clients to use in their error handling logic.
// It is built from a namespace / resource (e.g., "user") and a specific error condition (e.g., "already_exists"), separated by a dot.
string slug = 1;
// The message is a human-readable message in English.
// This message is intended for developers and should provide a clear explanation of the error.
// It is not meant for end-users and should not be localized.
// Clients are encouraged not to present this to their end-users, but rather use their own translation logic based on the slug.
string message = 2;
// The details field is a structured object that can contain additional information about the error.
// It is intended to provide more context for developers and can include any relevant data that may help in diagnosing the issue
// or clients can use it to provide additional context in their error handling logic.
// The content of the details field is not standardized and can vary depending on the error type.
// While object details should remain consistent across versions, there's no guarantee that the structure will remain unchanged,
// so clients should not rely on a specific structure within the details field.
google.protobuf.Struct details = 3;
}
@@ -7,6 +7,7 @@ import "zitadel/object/v2/object.proto";
import "zitadel/protoc_gen_zitadel/v2/options.proto";
import "zitadel/session/v2/challenge.proto";
import "zitadel/session/v2/session.proto";
import "zitadel/error/v2/error.proto";
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
import "google/protobuf/struct.proto";
@@ -257,6 +258,11 @@ service SessionService {
// Required permissions:
// - `session.delete`
// - no permission required for own sessions or when providing the current session token
//
// Possible error slugs include (non-exhaustive):
// - "request.invalid" when required fields such as the session ID are missing or invalid
// - "auth.missing_permission" when the caller does not have the required permissions to delete the session
// - "session.token_invalid" when the provided session token is invalid
rpc DeleteSession (DeleteSessionRequest) returns (DeleteSessionResponse) {
option (google.api.http) = {
delete: "/v2/sessions/{session_id}"