The error endpoint retrieves detailed information about errors that occur during self-service flows. When a flow encounters an error, Kratos redirects to your error UI with an error ID, which you can use to fetch the error details.
Get flow error
curl -X GET 'https://your-project.projects.oryapis.com/self-service/errors?id=a3c48c1e-62a0-4a8a-9b3e-1f9c7d5e2b4a' \
-H 'Content-Type: application/json'
Retrieve the error associated with a user-facing self-service error. This endpoint returns error details that can be displayed to users.
Method and path
Authentication
No authentication required.
Request parameters
The error’s ID. This is provided in the error query parameter when Kratos redirects to your error UI. For testing, use stub value stub:500 to get a stub Internal Server Error.
Response
ID of the error container
The error details HTTP status code (e.g., 400, 404, 500)
HTTP status description (e.g., “Bad Request”, “Not Found”)
The error message - a human-readable description of what went wrong
A more detailed, human-readable reason for the error
Error ID - useful for identifying various errors in application logic
Debug information. Often not exposed to end users to prevent leaking sensitive information.
The request ID - often exposed internally to trace errors across service architectures. Usually a UUID.
Further error details as key-value pairs
When the error was created
When the error was last updated
Example response
{
"id" : "a3c48c1e-62a0-4a8a-9b3e-1f9c7d5e2b4a" ,
"error" : {
"code" : 400 ,
"status" : "Bad Request" ,
"message" : "The request was malformed or invalid" ,
"reason" : "The email address provided is already in use" ,
"id" : "duplicate_credentials" ,
"request" : "d7ef54b1-ec15-46e6-bccb-524b82c035e6"
},
"created_at" : "2026-03-03T15:30:00Z" ,
"updated_at" : "2026-03-03T15:30:00Z"
}
Error responses
Forbidden - Access denied to this error
Not Found - Error ID does not exist or has expired
Error flow in self-service
When an error occurs during a self-service flow (login, registration, recovery, verification, or settings), Kratos follows this process:
Error occurs - Something goes wrong during the flow (e.g., validation error, network issue, internal error)
Kratos redirects - Kratos redirects the browser to your configured error UI URL with the error ID:
https://your-app.com/error?id=a3c48c1e-62a0-4a8a-9b3e-1f9c7d5e2b4a
Fetch error details - Your error UI calls this endpoint to get the error details:
GET /self-service/errors?id=a3c48c1e-62a0-4a8a-9b3e-1f9c7d5e2b4a
Display to user - Show the error message to the user in a friendly format
Displaying errors to users
When displaying errors to users, follow these best practices:
Show user-friendly messages
Use the message and reason fields to display helpful information:
const errorData = await fetch (
`https://your-kratos-url/self-service/errors?id= ${ errorId } `
). then ( r => r . json ());
const displayMessage = errorData . error . reason || errorData . error . message ;
Handle different error types
Common error scenarios in self-service flows:
Status: 400 Bad RequestCause: Invalid input (e.g., weak password, invalid email format)Action: Display the validation message and allow the user to correct their input
Status: 400 Bad RequestCause: Email or username already existsAction: Inform the user and suggest login or account recovery
Status: 410 GoneCause: The self-service flow took too long and expiredAction: Redirect to start a new flow
Status: 500 Internal Server ErrorCause: Server-side issueAction: Show a generic error message and provide a way to contact support
Example error UI implementation
import { useSearchParams } from 'react-router-dom' ;
import { useEffect , useState } from 'react' ;
export function ErrorPage () {
const [ searchParams ] = useSearchParams ();
const errorId = searchParams . get ( 'id' );
const [ error , setError ] = useState ( null );
const [ loading , setLoading ] = useState ( true );
useEffect (() => {
if ( ! errorId ) {
setLoading ( false );
return ;
}
fetch ( `https://your-kratos-url/self-service/errors?id= ${ errorId } ` )
. then ( res => res . json ())
. then ( data => {
setError ( data . error );
setLoading ( false );
})
. catch ( err => {
console . error ( 'Failed to fetch error:' , err );
setLoading ( false );
});
}, [ errorId ]);
if ( loading ) {
return < div > Loading... </ div > ;
}
if ( ! error ) {
return < div > An unknown error occurred </ div > ;
}
return (
< div className = "error-container" >
< h1 > Oops! Something went wrong </ h1 >
< p > { error . reason || error . message } </ p >
{ error . code === 410 && (
< p >
This flow has expired. Please < a href = "/login" > start over </ a > .
</ p >
) }
{ error . code >= 500 && (
< p >
We're experiencing technical difficulties. Please try again later
or < a href = "/support" > contact support </ a > with error ID: { error . id }
</ p >
) }
< button onClick = { () => window . history . back () } >
Go Back
</ button >
</ div >
);
}
Testing error handling
Kratos provides stub error IDs for testing your error UI:
curl -X GET 'https://your-project.projects.oryapis.com/self-service/errors?id=stub:500' \
-H 'Content-Type: application/json'
This returns a sample 500 Internal Server Error that you can use to test your error display logic.
Configuration
Configure the error UI URL in your Kratos configuration:
selfservice :
flows :
error :
ui_url : https://your-app.com/error
For more information, see the User-Facing Errors documentation .