Repository: Tochemey/goakt
Pull request #117 (2023-09-13 10:53:27)

refactor!: change some functions signature because init failure

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/Tochemey/goakt/pull/117?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) Report
Patch coverage: **`90.90%`** and project coverage change: **`+0.85%`** :tada:
> Comparison is base [(`3b70b4b`)](https://app.codecov.io/gh/Tochemey/goakt/commit/3b70b4bd535f35927ef44ebc548bad96c334bae7?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) 87.56% compared to head [(`8d91c0e`)](https://app.codecov.io/gh/Tochemey/goakt/pull/117?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) 88.41%.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #117      +/-   ##
==========================================
+ Coverage   87.56%   88.41%   +0.85%     
==========================================
  Files          38       38              
  Lines        3272     3288      +16     
==========================================
+ Hits         2865     2907      +42     
+ Misses        314      294      -20     
+ Partials       93       87       -6     
```


| [Files Changed](https://app.codecov.io/gh/Tochemey/goakt/pull/117?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) | Coverage Δ | |
|---|---|---|
| [actors/errors.go](https://app.codecov.io/gh/Tochemey/goakt/pull/117?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL2Vycm9ycy5nbw==) | `87.50% <80.00%> (+1.78%)` | :arrow_up: |
| [actors/pid.go](https://app.codecov.io/gh/Tochemey/goakt/pull/117?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL3BpZC5nbw==) | `90.54% <91.17%> (+2.42%)` | :arrow_up: |
| [actors/actor\_system.go](https://app.codecov.io/gh/Tochemey/goakt/pull/117?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL2FjdG9yX3N5c3RlbS5nbw==) | `87.26% <91.89%> (+1.47%)` | :arrow_up: |
| [actors/reflection.go](https://app.codecov.io/gh/Tochemey/goakt/pull/117?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL3JlZmxlY3Rpb24uZ28=) | `87.50% <100.00%> (ø)` | |

... and [2 files with indirect coverage changes](https://app.codecov.io/gh/Tochemey/goakt/pull/117/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene)


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/Tochemey/goakt/pull/117?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene).


Patch:
diff --git a/actors/actor.go b/actors/actor.go
index 12df8e3..97d81f2 100644
--- a/actors/actor.go
+++ b/actors/actor.go
@@ -8,7 +8,8 @@ import (
 // This will be implemented by any user who wants to create an actor
 type Actor interface {
 	// PreStart pre-starts the actor. This function can be used to set up some database connections
-	// or some sort of initialization before the actor start processing public
+	// or some sort of initialization before the actor start processing messages
+	// when the initialization failed the actor will not be started
 	PreStart(ctx context.Context) error
 	// Receive processes any message dropped into the actor mailbox.
 	// The receiver of any message can either reply to the sender of the message with a new message or reply to the message synchronously
diff --git a/actors/actor_system.go b/actors/actor_system.go
index 58f23a9..638751b 100644
--- a/actors/actor_system.go
+++ b/actors/actor_system.go
@@ -41,7 +41,7 @@ type ActorSystem interface {
 	// Stop stops the actor system
 	Stop(ctx context.Context) error
 	// Spawn creates an actor in the system and starts it
-	Spawn(ctx context.Context, name string, actor Actor) PID
+	Spawn(ctx context.Context, name string, actor Actor) (PID, error)
 	// Kill stops a given actor in the system
 	Kill(ctx context.Context, name string) error
 	// ReSpawn recreates a given actor in the system
@@ -208,13 +208,13 @@ func (x *actorSystem) NumActors() uint64 {
 }
 
 // Spawn creates or returns the instance of a given actor in the system
-func (x *actorSystem) Spawn(ctx context.Context, name string, actor Actor) PID {
+func (x *actorSystem) Spawn(ctx context.Context, name string, actor Actor) (PID, error) {
 	// add a span context
 	ctx, span := telemetry.SpanContext(ctx, "Spawn")
 	defer span.End()
 	// first check whether the actor system has started
 	if !x.hasStarted.Load() {
-		return nil
+		return nil, ErrActorSystemNotStarted
 	}
 	// set the default actor path assuming we are running locally
 	actorPath := NewPath(name, NewAddress(x.name, "", -1))
@@ -230,12 +230,12 @@ func (x *actorSystem) Spawn(ctx context.Context, name string, actor Actor) PID {
 		// check whether the given actor heart beat
 		if pid.IsRunning() {
 			// return the existing instance
-			return pid
+			return pid, nil
 		}
 	}
 
 	// create an instance of the actor ref
-	pid = newPID(ctx,
+	pid, err := newPID(ctx,
 		actorPath,
 		actor,
 		withInitMaxRetries(x.actorInitMaxRetries),
@@ -249,6 +249,11 @@ func (x *actorSystem) Spawn(ctx context.Context, name string, actor Actor) PID {
 		withStash(x.stashBuffer),
 		withTelemetry(x.telemetry))
 
+	// handle the error
+	if err != nil {
+		return nil, err
+	}
+
 	// add the given actor to the actor map
 	x.actors.Set(actorPath.String(), pid)
 
@@ -266,7 +271,7 @@ func (x *actorSystem) Spawn(ctx context.Context, name string, actor Actor) PID {
 	}
 
 	// return the actor ref
-	return pid
+	return pid, nil
 }
 
 // Kill stops a given actor in the system
@@ -276,7 +281,7 @@ func (x *actorSystem) Kill(ctx context.Context, name string) error {
 	defer span.End()
 	// first check whether the actor system has started
 	if !x.hasStarted.Load() {
-		return errors.New("actor system has not started yet")
+		return ErrActorSystemNotStarted
 	}
 	// set the default actor path assuming we are running locally
 	actorPath := NewPath(name, NewAddress(x.name, "", -1))
@@ -302,7 +307,7 @@ func (x *actorSystem) ReSpawn(ctx context.Context, name string) (PID, error) {
 	defer span.End()
 	// first check whether the actor system has started
 	if !x.hasStarted.Load() {
-		return nil, errors.New("actor system has not started yet")
+		return nil, ErrActorSystemNotStarted
 	}
 	// set the default actor path assuming we are running locally
 	actorPath := NewPath(name, NewAddress(x.name, "", -1))
@@ -368,6 +373,11 @@ func (x *actorSystem) ActorOf(ctx context.Context, actorName string) (addr *addr
 	ctx, span := telemetry.SpanContext(ctx, "ActorOf")
 	defer span.End()
 
+	// make sure the actor system has started
+	if !x.hasStarted.Load() {
+		return nil, nil, ErrActorSystemNotStarted
+	}
+
 	// try to locate the actor in the cluster when cluster is enabled
 	if x.cluster != nil || x.clusterEnabled.Load() {
 		// let us locate the actor in the cluster
@@ -415,6 +425,12 @@ func (x *actorSystem) LocalActor(ctx context.Context, actorName string) (PID, er
 	// add a span context
 	ctx, span := telemetry.SpanContext(ctx, "LocalActor")
 	defer span.End()
+
+	// make sure the actor system has started
+	if !x.hasStarted.Load() {
+		return nil, ErrActorSystemNotStarted
+	}
+
 	// first let us do a local lookup
 	items := x.actors.Items()
 	// iterate the local actors storage
@@ -440,9 +456,15 @@ func (x *actorSystem) RemoteActor(ctx context.Context, actorName string) (addr *
 	// add a span context
 	ctx, span := telemetry.SpanContext(ctx, "RemoteActor")
 	defer span.End()
+
+	// make sure the actor system has started
+	if !x.hasStarted.Load() {
+		return nil, ErrActorSystemNotStarted
+	}
+
 	// check whether cluster is enabled or not
 	if x.cluster == nil {
-		return nil, ErrClusterNotEnabled
+		return nil, ErrClusterDisabled
 	}
 
 	// let us locate the actor in the cluster
@@ -494,16 +516,21 @@ func (x *actorSystem) Start(ctx context.Context) error {
 
 // Stop stops the actor system
 func (x *actorSystem) Stop(ctx context.Context) error {
+	// add a span context
+	ctx, span := telemetry.SpanContext(ctx, "Stop")
+	defer span.End()
+
+	// make sure the actor system has started
+	if !x.hasStarted.Load() {
+		return ErrActorSystemNotStarted
+	}
+
 	// create a cancellation context to gracefully shutdown
 	ctx, cancel := context.WithTimeout(ctx, x.shutdownTimeout)
 	defer cancel()
 
 	// stop the housekeeper
 	x.housekeeperStopSig <- Unit{}
-
-	// add a span context
-	ctx, span := telemetry.SpanContext(ctx, "Shutdown")
-	defer span.End()
 	x.logger.Infof("%s is shutting down..:)", x.name)
 
 	// set started to false
@@ -572,7 +599,7 @@ func (x *actorSystem) RemoteLookup(ctx context.Context, request *connect.Request
 
 	// set the actor path with the remoting is enabled
 	if !x.remotingEnabled.Load() {
-		return nil, connect.NewError(connect.CodeFailedPrecondition, ErrRemotingNotEnabled)
+		return nil, connect.NewError(connect.CodeFailedPrecondition, ErrRemotingDisabled)
 	}
 
 	// get the remoting server address
@@ -621,7 +648,7 @@ func (x *actorSystem) RemoteAsk(ctx context.Context, request *connect.Request[in
 
 	// set the actor path with the remoting is enabled
 	if !x.remotingEnabled.Load() {
-		return nil, connect.NewError(connect.CodeFailedPrecondition, ErrRemotingNotEnabled)
+		return nil, connect.NewError(connect.CodeFailedPrecondition, ErrRemotingDisabled)
 	}
 
 	// get the remoting server address
@@ -649,12 +676,6 @@ func (x *actorSystem) RemoteAsk(ctx context.Context, request *connect.Request[in
 		logger.Error(ErrAddressNotFound(actorPath.String()).Error())
 		return nil, ErrAddressNotFound(actorPath.String())
 	}
-	// restart the actor when it is not live
-	if !pid.IsRunning() {
-		if err := pid.Restart(ctx); err != nil {
-			return nil, err
-		}
-	}
 
 	// send the message to actor
 	reply, err := x.handleRemoteAsk(ctx, pid, reqCopy.GetRemoteMessage())
@@ -685,7 +706,7 @@ func (x *actorSystem) RemoteTell(ctx context.Context, request *connect.Request[i
 
 	// set the actor path with the remoting is enabled
 	if !x.remotingEnabled.Load() {
-		return nil, connect.NewError(connect.CodeFailedPrecondition, ErrRemotingNotEnabled)
+		return nil, connect.NewError(connect.CodeFailedPrecondition, ErrRemotingDisabled)
 	}
 
 	// get the remoting server address
@@ -716,12 +737,6 @@ func (x *actorSystem) RemoteTell(ctx context.Context, request *connect.Request[i
 		logger.Error(ErrAddressNotFound(actorPath.String()).Error())
 		return nil, ErrAddressNotFound(actorPath.String())
 	}
-	// restart the actor when it is not live
-	if !pid.IsRunning() {
-		if err := pid.Restart(ctx); err != nil {
-			return nil, err
-		}
-	}
 
 	// send the message to actor
 	if err := x.handleRemoteTell(ctx, pid, reqCopy.GetRemoteMessage()); err != nil {
diff --git a/actors/errors.go b/actors/errors.go
index d0d31f6..fe71d69 100644
--- a/actors/errors.go
+++ b/actors/errors.go
@@ -11,20 +11,22 @@ var (
 	ErrInvalidActorSystemName = errors.New("invalid ActorSystem name, must contain only word characters (i.e. [a-zA-Z0-9] plus non-leading '-' or '_')")
 	ErrDead                   = errors.New("actor is not alive")
 	ErrUnhandled              = errors.New("unhandled message")
-	ErrClusterNotEnabled      = errors.New("cluster is not enabled")
+	ErrClusterDisabled        = errors.New("cluster is not enabled")
 	ErrUndefinedActor         = errors.New("actor is not defined")
 	ErrRequestTimeout         = errors.New("request timed out")
-	ErrRemotingNotEnabled     = errors.New("remoting is not enabled")
+	ErrRemotingDisabled       = errors.New("remoting is not enabled")
 	ErrInvalidActorSystemNode = connect.NewError(connect.CodeFailedPrecondition, errors.New("invalid actor system node"))
 	ErrAddressNotFound        = func(addr string) error {
 		return connect.NewError(connect.CodeNotFound, fmt.Errorf("actor=%s not found", addr))
 	}
-	ErrRemoteSendFailure    = func(err error) error { return connect.NewError(connect.CodeInternal, err) }
-	ErrInstanceNotAnActor   = errors.New("failed to create instance. Reason: instance does not implement the Actor interface")
-	ErrInvalidInstance      = errors.New("failed to create instance. Reason: invalid instance")
-	ErrTypeNotFound         = func(typeName string) error { return fmt.Errorf("typeName=%s not found", typeName) }
-	ErrActorNotFound        = func(actorPath string) error { return fmt.Errorf("actor=%s not found", actorPath) }
-	ErrMethodCallNotAllowed = errors.New("method call not allowed")
-	ErrInvalidRemoteMessage = func(err error) error { return errors.Wrap(err, "invalid remote message") }
-	ErrStashBufferNotSet    = errors.New("actor is not setup with a stash buffer")
+	ErrRemoteSendFailure     = func(err error) error { return connect.NewError(connect.CodeInternal, err) }
+	ErrInvalidActorInterface = errors.New("failed to create instance. Reason: instance does not implement the Actor interface")
+	ErrInvalidInstance       = errors.New("failed to create instance. Reason: invalid instance")
+	ErrTypeNotFound          = func(typeName string) error { return fmt.Errorf("typeName=%s not found", typeName) }
+	ErrActorNotFound         = func(actorPath string) error { return fmt.Errorf("actor=%s not found", actorPath) }
+	ErrMethodCallNotAllowed  = errors.New("method call not allowed")
+	ErrInvalidRemoteMessage  = func(err error) error { return errors.Wrap(err, "invalid remote message") }
+	ErrStashBufferNotSet     = errors.New("actor is not setup with a stash buffer")
+	ErrInitFailure           = func(err error) error { return errors.Wrap(err, "failed to initialize") }
+	ErrActorSystemNotStarted = errors.New("actor system has not started yet")
 )
diff --git a/actors/pid.go b/actors/pid.go
index 04d277e..890491d 100644
--- a/actors/pid.go
+++ b/actors/pid.go
@@ -23,8 +23,6 @@ import (
 	"go.opentelemetry.io/otel/attribute"
 	"go.opentelemetry.io/otel/metric"
 	"go.uber.org/atomic"
-	"google.golang.org/grpc/codes"
-	"google.golang.org/grpc/status"
 	"google.golang.org/protobuf/proto"
 	"google.golang.org/protobuf/types/known/anypb"
 )
@@ -76,6 +74,7 @@ type PID interface {
 	// at a given point in time while the actor heart is still beating
 	ErrorsCount(ctx context.Context) uint64
 	// SpawnChild creates a child actor
+	// When the given child actor already exists its PID will only be returned
 	SpawnChild(ctx context.Context, name string, actor Actor) (PID, error)
 	// Restart restarts the actor
 	Restart(ctx context.Context) error
@@ -224,7 +223,7 @@ type pid struct {
 var _ PID = (*pid)(nil)
 
 // newPID creates a new pid
-func newPID(ctx context.Context, actorPath *Path, actor Actor, opts ...pidOption) *pid {
+func newPID(ctx context.Context, actorPath *Path, actor Actor, opts ...pidOption) (*pid, error) {
 	// add a span context
 	ctx, span := telemetry.SpanContext(ctx, "NewPID")
 	defer span.End()
@@ -280,7 +279,9 @@ func newPID(ctx context.Context, actorPath *Path, actor Actor, opts ...pidOption
 	pid.behaviorStack = behaviorStack
 
 	// initialize the actor and init processing public
-	pid.init(ctx)
+	if err := pid.init(ctx); err != nil {
+		return nil, err
+	}
 	// init processing public
 	go pid.receive()
 	// init the passivation listener loop iff passivation is set
@@ -295,7 +296,7 @@ func newPID(ctx context.Context, actorPath *Path, actor Actor, opts ...pidOption
 	}
 
 	// return the actor reference
-	return pid
+	return pid, nil
 }
 
 // ActorHandle returns the underlying Actor
@@ -319,10 +320,6 @@ func (p *pid) Child(ctx context.Context, name string) (PID, error) {
 
 	// check whether the child actor already exist and just return the PID
 	if cid, ok := p.children.Get(childActorPath); ok {
-		// check whether the actor is stopped
-		if cid != nil && !cid.IsRunning() {
-			return nil, ErrDead
-		}
 		return cid, nil
 	}
 	return nil, ErrActorNotFound(childActorPath.String())
@@ -367,10 +364,13 @@ func (p *pid) Stop(ctx context.Context, pid PID) error {
 
 	// grab the actor path
 	path := pid.ActorPath()
-	if cid, ok := p.children.Get(path); ok {
-		if !cid.IsRunning() {
-			return nil
-		}
+
+	// grab the children thread-safely
+	p.pidSemaphore.RLock()
+	kiddos := p.children
+	p.pidSemaphore.RUnlock()
+
+	if cid, ok := kiddos.Get(path); ok {
 		// stop the actor
 		return cid.Shutdown(ctx)
 	}
@@ -399,21 +399,21 @@ func (p *pid) ActorPath() *Path {
 	return path
 }
 
-// Restart restarts the actor. This call can panic which is the expected behaviour.
+// Restart restarts the actor.
 // During restart all messages that are in the mailbox and not yet processed will be ignored
 func (p *pid) Restart(ctx context.Context) error {
 	// add a span context
 	ctx, span := telemetry.SpanContext(ctx, "Restart")
 	defer span.End()
 
-	// add some debug logging
-	p.logger.Debugf("restarting actor=(%s)", p.actorPath.String())
-
 	// first check whether we have an empty PID
 	if p == nil || p.ActorPath() == nil {
 		return ErrUndefinedActor
 	}
 
+	// add some debug logging
+	p.logger.Debugf("restarting actor=(%s)", p.actorPath.String())
+
 	// only restart the actor when the actor is running
 	if p.IsRunning() {
 		// shutdown the actor
@@ -442,7 +442,9 @@ func (p *pid) Restart(ctx context.Context) error {
 	// reset the behavior
 	p.resetBehavior()
 	// initialize the actor
-	p.init(ctx)
+	if err := p.init(ctx); err != nil {
+		return err
+	}
 	// init processing public
 	go p.receive()
 	// init the passivation listener loop iff passivation is set
@@ -463,6 +465,7 @@ func (p *pid) Restart(ctx context.Context) error {
 }
 
 // SpawnChild creates a child actor and start watching it for error
+// When the given child actor already exists its PID will only be returned
 func (p *pid) SpawnChild(ctx context.Context, name string, actor Actor) (PID, error) {
 	// add a span context
 	ctx, span := telemetry.SpanContext(ctx, "SpawnChild")
@@ -475,15 +478,14 @@ func (p *pid) SpawnChild(ctx context.Context, name string, actor Actor) (PID, er
 	// create the child actor path
 	childActorPath := NewPath(name, p.ActorPath().Address()).WithParent(p.ActorPath())
 
+	// grab the children thread-safely
+	p.pidSemaphore.RLock()
+	kiddos := p.children
+	p.pidSemaphore.RUnlock()
+
 	// check whether the child actor already exist and just return the PID
-	if cid, ok := p.children.Get(childActorPath); ok {
-		// check whether the actor is stopped
-		if cid != nil && !cid.IsRunning() {
-			// then reboot it
-			if err := cid.Restart(ctx); err != nil {
-				return nil, err
-			}
-		}
+	// whenever a child actor exists it means it is live
+	if cid, ok := kiddos.Get(childActorPath); ok {
 		return cid, nil
 	}
 
@@ -493,7 +495,7 @@ func (p *pid) SpawnChild(ctx context.Context, name string, actor Actor) (PID, er
 	defer p.pidSemaphore.Unlock()
 
 	// create the child pid
-	cid := newPID(ctx,
+	cid, err := newPID(ctx,
 		childActorPath,
 		actor,
 		withInitMaxRetries(int(p.initMaxRetries.Load())),
@@ -507,6 +509,11 @@ func (p *pid) SpawnChild(ctx context.Context, name string, actor Actor) (PID, er
 		withMailbox(p.mailbox.Clone()),
 		withShutdownTimeout(p.shutdownTimeout.Load()))
 
+	// handle the error
+	if err != nil {
+		return nil, err
+	}
+
 	// add the pid to the map
 	p.children.Set(cid)
 
@@ -659,9 +666,8 @@ func (p *pid) RemoteLookup(ctx context.Context, host string, port int, name stri
 	response, err := remoteClient.RemoteLookup(ctx, request)
 	// we know the error will always be a grpc error
 	if err != nil {
-		// get the status error
-		s := status.Convert(err)
-		if s.Code() == codes.NotFound {
+		code := connect.CodeOf(err)
+		if code == connect.CodeNotFound {
 			return nil, nil
 		}
 		return nil, err
@@ -860,9 +866,9 @@ func (p *pid) doReceive(ctx ReceiveContext) {
 	p.receivedMessageCounter.Inc()
 }
 
-// init initializes the given actor and init processing public
-// when the initialization failed the actor is automatically shutdown
-func (p *pid) init(ctx context.Context) {
+// init initializes the given actor and init processing messages
+// when the initialization failed the actor will not be started
+func (p *pid) init(ctx context.Context) error {
 	// add a span context
 	ctx, span := telemetry.SpanContext(ctx, "Init")
 	defer span.End()
@@ -876,9 +882,7 @@ func (p *pid) init(ctx context.Context) {
 	}, expoBackoff)
 	// handle backoff error
 	if err != nil {
-		// log the error
-		p.logger.Error(err.Error())
-		return
+		return ErrInitFailure(err)
 	}
 	// set the actor is ready
 	p.pidSemaphore.Lock()
@@ -888,6 +892,7 @@ func (p *pid) init(ctx context.Context) {
 	p.pidSemaphore.Unlock()
 	// add some logging info
 	p.logger.Info("Initialization process successfully completed.")
+	return nil
 }
 
 // reset re-initializes the actor PID
diff --git a/actors/reflection.go b/actors/reflection.go
index 3480531..0e27836 100644
--- a/actors/reflection.go
+++ b/actors/reflection.go
@@ -33,7 +33,7 @@ func (r *reflection) ActorOf(rtype reflect.Type) (actor Actor, err error) {
 	isActor := rtype.Implements(iface) || reflect.PtrTo(rtype).Implements(iface)
 	// reject the creation of the instance
 	if !isActor {
-		return nil, ErrInstanceNotAnActor
+		return nil, ErrInvalidActorInterface
 	}
 	// get the type value of the object type
 	typVal := reflect.New(rtype)
diff --git a/examples/actor-cluster/k8s/service/service.go b/examples/actor-cluster/k8s/service/service.go
index 96587c7..f54aeb4 100644
--- a/examples/actor-cluster/k8s/service/service.go
+++ b/examples/actor-cluster/k8s/service/service.go
@@ -44,7 +44,10 @@ func (s *AccountService) CreateAccount(ctx context.Context, c *connect.Request[s
 	// create the pid and send the command create account
 	accountEntity := kactors.NewAccountEntity(req.GetCreateAccount().GetAccountId())
 	// create the given pid
-	pid := s.actorSystem.Spawn(ctx, accountID, accountEntity)
+	pid, err := s.actorSystem.Spawn(ctx, accountID, accountEntity)
+	if err != nil {
+		return nil, err
+	}
 	// send the create command to the pid
 	reply, err := actors.Ask(ctx, pid, &samplepb.CreateAccount{
 		AccountId:      accountID,
diff --git a/examples/actor-observability/main.go b/examples/actor-observability/main.go
index d82360d..0c50257 100644
--- a/examples/actor-observability/main.go
+++ b/examples/actor-observability/main.go
@@ -85,8 +85,8 @@ func main() {
 	_ = actorSystem.Start(ctx)
 
 	// create an actor
-	pingActor := actorSystem.Spawn(ctx, "Ping", NewPingActor())
-	pongActor := actorSystem.Spawn(ctx, "Pong", NewPongActor())
+	pingActor, _ := actorSystem.Spawn(ctx, "Ping", NewPingActor())
+	pongActor, _ := actorSystem.Spawn(ctx, "Pong", NewPongActor())
 
 	// start the conversation
 	_ = pingActor.Tell(ctx, pongActor, new(samplepb.Ping))
diff --git a/examples/actor-receive/main.go b/examples/actor-receive/main.go
index 4670dd1..7b360db 100644
--- a/examples/actor-receive/main.go
+++ b/examples/actor-receive/main.go
@@ -30,7 +30,7 @@ func main() {
 	_ = actorSystem.Start(ctx)
 
 	// create an actor
-	actor := actorSystem.Spawn(ctx, "Ping", NewPinger())
+	actor, _ := actorSystem.Spawn(ctx, "Ping", NewPinger())
 
 	startTime := time.Now()
 
diff --git a/examples/actor-to-actor/main.go b/examples/actor-to-actor/main.go
index f397e4c..038e774 100644
--- a/examples/actor-to-actor/main.go
+++ b/examples/actor-to-actor/main.go
@@ -29,8 +29,8 @@ func main() {
 	_ = actorSystem.Start(ctx)
 
 	// create an actor
-	pingActor := actorSystem.Spawn(ctx, "Ping", NewPingActor())
-	pongActor := actorSystem.Spawn(ctx, "Pong", NewPongActor())
+	pingActor, _ := actorSystem.Spawn(ctx, "Ping", NewPingActor())
+	pongActor, _ := actorSystem.Spawn(ctx, "Pong", NewPongActor())
 
 	// start the conversation
 	_ = pingActor.Tell(ctx, pongActor, new(samplepb.Ping))
diff --git a/examples/remoting/ping/main.go b/examples/remoting/ping/main.go
index 53e3f5c..93aa413 100644
--- a/examples/remoting/ping/main.go
+++ b/examples/remoting/ping/main.go
@@ -36,7 +36,7 @@ func main() {
 	_ = actorSystem.Start(ctx)
 
 	// create an actor
-	pingActor := actorSystem.Spawn(ctx, "Ping", NewPingActor())
+	pingActor, _ := actorSystem.Spawn(ctx, "Ping", NewPingActor())
 
 	// start the conversation
 	timer := time.AfterFunc(time.Second, func() {
diff --git a/examples/remoting/pong/main.go b/examples/remoting/pong/main.go
index 781ce71..169984b 100644
--- a/examples/remoting/pong/main.go
+++ b/examples/remoting/pong/main.go
@@ -34,7 +34,7 @@ func main() {
 	_ = actorSystem.Start(ctx)
 
 	// create an actor
-	actorSystem.Spawn(ctx, "Pong", NewPongActor(logger))
+	_, _ = actorSystem.Spawn(ctx, "Pong", NewPongActor(logger))
 
 	// capture ctrl+c
 	interruptSignal := make(chan os.Signal, 1)


Test patch:
diff --git a/actors/actor_system_test.go b/actors/actor_system_test.go
index 15264b7..03ff580 100644
--- a/actors/actor_system_test.go
+++ b/actors/actor_system_test.go
@@ -47,7 +47,9 @@ func TestActorSystem(t *testing.T) {
 		ctx := context.TODO()
 		sys, _ := NewActorSystem("testSys", WithLogger(log.DiscardLogger))
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, "Test", actor)
+		actorRef, err := sys.Spawn(ctx, "Test", actor)
+		assert.Error(t, err)
+		assert.EqualError(t, err, ErrActorSystemNotStarted.Error())
 		assert.Nil(t, actorRef)
 	})
 	t.Run("With Spawn an actor when started", func(t *testing.T) {
@@ -59,7 +61,8 @@ func TestActorSystem(t *testing.T) {
 		assert.NoError(t, err)
 
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, "Test", actor)
+		actorRef, err := sys.Spawn(ctx, "Test", actor)
+		assert.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// stop the actor after some time
@@ -79,11 +82,13 @@ func TestActorSystem(t *testing.T) {
 		assert.NoError(t, err)
 
 		actor := NewTester()
-		ref1 := sys.Spawn(ctx, "Test", actor)
+		ref1, err := sys.Spawn(ctx, "Test", actor)
+		assert.NoError(t, err)
 		assert.NotNil(t, ref1)
 
-		ref2 := sys.Spawn(ctx, "Test", actor)
+		ref2, err := sys.Spawn(ctx, "Test", actor)
 		assert.NotNil(t, ref2)
+		assert.NoError(t, err)
 
 		// point to the same memory address
 		assert.True(t, ref1 == ref2)
@@ -151,7 +156,8 @@ func TestActorSystem(t *testing.T) {
 		// create an actor
 		actorName := uuid.NewString()
 		actor := NewTester()
-		actorRef := newActorSystem.Spawn(ctx, actorName, actor)
+		actorRef, err := newActorSystem.Spawn(ctx, actorName, actor)
+		assert.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// wait for a while for replication to take effect
@@ -219,7 +225,8 @@ func TestActorSystem(t *testing.T) {
 		// create an actor
 		actorName := uuid.NewString()
 		actor := NewTester()
-		actorRef := newActorSystem.Spawn(ctx, actorName, actor)
+		actorRef, err := newActorSystem.Spawn(ctx, actorName, actor)
+		assert.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		path := NewPath(actorName, &Address{
@@ -266,7 +273,8 @@ func TestActorSystem(t *testing.T) {
 
 		actorName := "testActor"
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, actorName, actor)
+		actorRef, err := sys.Spawn(ctx, actorName, actor)
+		assert.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		addr, pid, err := sys.ActorOf(ctx, actorName)
@@ -305,6 +313,30 @@ func TestActorSystem(t *testing.T) {
 			assert.NoError(t, err)
 		})
 	})
+	t.Run("With ActorOf actor system started", func(t *testing.T) {
+		ctx := context.TODO()
+		remotingPort := dynaport.Get(1)[0]
+
+		logger := log.New(log.DebugLevel, os.Stdout)
+		host := "localhost"
+
+		newActorSystem, err := NewActorSystem(
+			"test",
+			WithPassivationDisabled(),
+			WithLogger(logger),
+			WithReplyTimeout(time.Minute),
+			WithRemoting(host, int32(remotingPort)))
+		require.NoError(t, err)
+
+		// create an actor
+		actorName := uuid.NewString()
+
+		addr, pid, err := newActorSystem.ActorOf(ctx, actorName)
+		require.Error(t, err)
+		require.EqualError(t, err, ErrActorSystemNotStarted.Error())
+		require.Nil(t, addr)
+		require.Nil(t, pid)
+	})
 	t.Run("With ReSpawn", func(t *testing.T) {
 		ctx := context.TODO()
 		sys, _ := NewActorSystem("testSys", WithLogger(log.DiscardLogger))
@@ -314,7 +346,8 @@ func TestActorSystem(t *testing.T) {
 		assert.NoError(t, err)
 
 		actorName := "Exchanger"
-		actorRef := sys.Spawn(ctx, actorName, &Exchanger{})
+		actorRef, err := sys.Spawn(ctx, actorName, &Exchanger{})
+		assert.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// send a message to the actor
@@ -350,7 +383,8 @@ func TestActorSystem(t *testing.T) {
 		assert.NoError(t, err)
 
 		actorName := "Exchanger"
-		actorRef := sys.Spawn(ctx, actorName, &Exchanger{})
+		actorRef, err := sys.Spawn(ctx, actorName, &Exchanger{})
+		assert.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// send a message to the actor
@@ -404,7 +438,8 @@ func TestActorSystem(t *testing.T) {
 		require.NoError(t, err)
 
 		actorName := "Exchanger"
-		actorRef := newActorSystem.Spawn(ctx, actorName, &Exchanger{})
+		actorRef, err := newActorSystem.Spawn(ctx, actorName, &Exchanger{})
+		assert.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// send a message to the actor
@@ -440,7 +475,8 @@ func TestActorSystem(t *testing.T) {
 		assert.NoError(t, err)
 
 		actorName := "Exchanger"
-		actorRef := sys.Spawn(ctx, actorName, &Exchanger{})
+		actorRef, err := sys.Spawn(ctx, actorName, &Exchanger{})
+		assert.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// wait for the start of the actor to be complete
@@ -498,6 +534,46 @@ func TestActorSystem(t *testing.T) {
 			assert.NoError(t, err)
 		})
 	})
+	t.Run("With RemoteActor failure when system not started", func(t *testing.T) {
+		ctx := context.TODO()
+		remotingPort := dynaport.Get(1)[0]
+
+		logger := log.New(log.DebugLevel, os.Stdout)
+		host := "localhost"
+
+		newActorSystem, err := NewActorSystem(
+			"test",
+			WithPassivationDisabled(),
+			WithLogger(logger),
+			WithReplyTimeout(time.Minute),
+			WithRemoting(host, int32(remotingPort)))
+		require.NoError(t, err)
+
+		actorName := "some-actor"
+		remoteAddr, err := newActorSystem.RemoteActor(ctx, actorName)
+		require.Error(t, err)
+		require.EqualError(t, err, ErrActorSystemNotStarted.Error())
+		require.Nil(t, remoteAddr)
+	})
+	t.Run("With RemoteActor failure when system not started", func(t *testing.T) {
+		ctx := context.TODO()
+		remotingPort := dynaport.Get(1)[0]
+
+		logger := log.New(log.DebugLevel, os.Stdout)
+		host := "localhost"
+
+		newActorSystem, err := NewActorSystem(
+			"test",
+			WithPassivationDisabled(),
+			WithLogger(logger),
+			WithReplyTimeout(time.Minute),
+			WithRemoting(host, int32(remotingPort)))
+		require.NoError(t, err)
+
+		err = newActorSystem.Stop(ctx)
+		require.Error(t, err)
+		require.EqualError(t, err, ErrActorSystemNotStarted.Error())
+	})
 	t.Run("With RemoteActor failure when cluster is not enabled", func(t *testing.T) {
 		ctx := context.TODO()
 		remotingPort := dynaport.Get(1)[0]
@@ -521,7 +597,7 @@ func TestActorSystem(t *testing.T) {
 		actorName := "some-actor"
 		remoteAddr, err := newActorSystem.RemoteActor(ctx, actorName)
 		require.Error(t, err)
-		require.EqualError(t, err, ErrClusterNotEnabled.Error())
+		require.EqualError(t, err, ErrClusterDisabled.Error())
 		require.Nil(t, remoteAddr)
 
 		// stop the actor after some time
@@ -542,7 +618,8 @@ func TestActorSystem(t *testing.T) {
 
 		// create an actor
 		actorName := "Exchanger"
-		ref := sys.Spawn(ctx, actorName, &Exchanger{})
+		ref, err := sys.Spawn(ctx, actorName, &Exchanger{})
+		assert.NoError(t, err)
 		require.NotNil(t, ref)
 
 		// locate the actor
@@ -582,6 +659,19 @@ func TestActorSystem(t *testing.T) {
 			assert.NoError(t, err)
 		})
 	})
+	t.Run("With LocalActor when system not started", func(t *testing.T) {
+		ctx := context.TODO()
+		sys, _ := NewActorSystem("testSys", WithLogger(log.DiscardLogger))
+
+		// create an actor
+		actorName := "Exchanger"
+
+		// locate the actor
+		local, err := sys.LocalActor(ctx, actorName)
+		require.Error(t, err)
+		require.EqualError(t, err, ErrActorSystemNotStarted.Error())
+		require.Nil(t, local)
+	})
 	t.Run("With Kill an actor when not System started", func(t *testing.T) {
 		ctx := context.TODO()
 		sys, _ := NewActorSystem("testSys", WithLogger(log.DiscardLogger))
@@ -619,7 +709,8 @@ func TestActorSystem(t *testing.T) {
 
 		actorName := "HousekeeperActor"
 		actorHandler := NewTester()
-		actorRef := sys.Spawn(ctx, actorName, actorHandler)
+		actorRef, err := sys.Spawn(ctx, actorName, actorHandler)
+		assert.NoError(t, err)
 		require.NotNil(t, actorRef)
 
 		// wait for the actor to properly start
diff --git a/actors/actor_test.go b/actors/actor_test.go
index 49f1b89..8cc2dd8 100644
--- a/actors/actor_test.go
+++ b/actors/actor_test.go
@@ -6,6 +6,8 @@ import (
 	"testing"
 	"time"
 
+	"github.com/pkg/errors"
+
 	testspb "github.com/tochemey/goakt/test/data/pb/v1"
 	"go.uber.org/goleak"
 )
@@ -234,3 +236,17 @@ func (x *Stasher) PostStop(context.Context) error {
 }
 
 var _ Actor = &Stasher{}
+
+type InitTester struct{}
+
+func (x *InitTester) PreStart(context.Context) error {
+	return errors.New("failed")
+}
+
+func (x *InitTester) Receive(ReceiveContext) {}
+
+func (x *InitTester) PostStop(context.Context) error {
+	return nil
+}
+
+var _ Actor = &InitTester{}
diff --git a/actors/api_test.go b/actors/api_test.go
index b6d1414..30533b3 100644
--- a/actors/api_test.go
+++ b/actors/api_test.go
@@ -39,7 +39,8 @@ func TestAsk(t *testing.T) {
 		// create a test actor
 		actorName := "test"
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, actorName, actor)
+		actorRef, err := sys.Spawn(ctx, actorName, actor)
+		require.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// create a message to send to the test actor
@@ -79,7 +80,8 @@ func TestAsk(t *testing.T) {
 		// create a test actor
 		actorName := "test"
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, actorName, actor)
+		actorRef, err := sys.Spawn(ctx, actorName, actor)
+		require.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// Shutdown the actor after some time
@@ -122,7 +124,8 @@ func TestAsk(t *testing.T) {
 		// create a test actor
 		actorName := "test"
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, actorName, actor)
+		actorRef, err := sys.Spawn(ctx, actorName, actor)
+		require.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		time.Sleep(time.Second)
@@ -167,7 +170,8 @@ func TestTell(t *testing.T) {
 		// create a test actor
 		actorName := "test"
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, actorName, actor)
+		actorRef, err := sys.Spawn(ctx, actorName, actor)
+		require.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		time.Sleep(time.Second)
@@ -208,7 +212,8 @@ func TestTell(t *testing.T) {
 		// create a test actor
 		actorName := "test"
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, actorName, actor)
+		actorRef, err := sys.Spawn(ctx, actorName, actor)
+		require.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// Shutdown the actor after some time
@@ -250,7 +255,8 @@ func TestTell(t *testing.T) {
 		// create a test actor
 		actorName := "test"
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, actorName, actor)
+		actorRef, err := sys.Spawn(ctx, actorName, actor)
+		require.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// create a message to send to the test actor
@@ -298,7 +304,8 @@ func TestRemoteTell(t *testing.T) {
 		// create a test actor
 		actorName := "test"
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, actorName, actor)
+		actorRef, err := sys.Spawn(ctx, actorName, actor)
+		require.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// get the address of the actor
@@ -349,7 +356,8 @@ func TestRemoteTell(t *testing.T) {
 		// create a test actor
 		actorName := "test"
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, actorName, actor)
+		actorRef, err := sys.Spawn(ctx, actorName, actor)
+		require.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// get the address of the actor
@@ -392,7 +400,8 @@ func TestRemoteTell(t *testing.T) {
 		// create a test actor
 		actorName := "test"
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, actorName, actor)
+		actorRef, err := sys.Spawn(ctx, actorName, actor)
+		require.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// create a wrong address
@@ -445,7 +454,8 @@ func TestRemoteAsk(t *testing.T) {
 		// create a test actor
 		actorName := "test"
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, actorName, actor)
+		actorRef, err := sys.Spawn(ctx, actorName, actor)
+		require.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// get the address of the actor
@@ -501,7 +511,8 @@ func TestRemoteAsk(t *testing.T) {
 		// create a test actor
 		actorName := "test"
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, actorName, actor)
+		actorRef, err := sys.Spawn(ctx, actorName, actor)
+		require.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// get the address of the actor
@@ -547,7 +558,8 @@ func TestRemoteAsk(t *testing.T) {
 		// create a test actor
 		actorName := "test"
 		actor := NewTester()
-		actorRef := sys.Spawn(ctx, actorName, actor)
+		actorRef, err := sys.Spawn(ctx, actorName, actor)
+		require.NoError(t, err)
 		assert.NotNil(t, actorRef)
 
 		// get the address of the actor
@@ -568,7 +580,46 @@ func TestRemoteAsk(t *testing.T) {
 
 		// stop the actor after some time
 		time.Sleep(time.Second)
+		t.Cleanup(func() {
+			assert.NoError(t, sys.Stop(ctx))
+		})
+	})
+}
 
-		err = sys.Stop(ctx)
+func TestAPIRemoteLookup(t *testing.T) {
+	t.Run("When remoting is not enabled", func(t *testing.T) {
+		// create the context
+		ctx := context.TODO()
+		// define the logger to use
+		logger := log.New(log.DebugLevel, os.Stdout)
+		// generate the remoting port
+		nodePorts := dynaport.Get(1)
+		remotingPort := nodePorts[0]
+		host := "0.0.0.0"
+
+		// create the actor system
+		sys, err := NewActorSystem("test",
+			WithLogger(logger),
+			WithPassivationDisabled(),
+		)
+		// assert there are no error
+		require.NoError(t, err)
+
+		// start the actor system
+		err = sys.Start(ctx)
+		assert.NoError(t, err)
+
+		time.Sleep(time.Second)
+
+		// create a test actor
+		actorName := "test"
+		// get the address of the actor
+		addr, err := RemoteLookup(ctx, host, remotingPort, actorName)
+		require.Error(t, err)
+		require.Nil(t, addr)
+
+		t.Cleanup(func() {
+			assert.NoError(t, sys.Stop(ctx))
+		})
 	})
 }
diff --git a/actors/context_test.go b/actors/context_test.go
index f4e07b3..7f3f519 100644
--- a/actors/context_test.go
+++ b/actors/context_test.go
@@ -28,7 +28,8 @@ func TestReceiveContext(t *testing.T) {
 		// create the actor path
 		actor := &UserActor{}
 		actorPath := NewPath("User", NewAddress("sys", "host", 1))
-		pid := newPID(ctx, actorPath, actor, opts...)
+		pid, err := newPID(ctx, actorPath, actor, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid)
 
 		// send Login
@@ -85,7 +86,8 @@ func TestReceiveContext(t *testing.T) {
 		// create actor1
 		actor1 := &Exchanger{}
 		actorPath1 := NewPath("Exchange1", NewAddress("sys", "host", 1))
-		pid1 := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create an instance of receive context
@@ -101,7 +103,8 @@ func TestReceiveContext(t *testing.T) {
 		// create actor2
 		actor2 := &Exchanger{}
 		actorPath2 := NewPath("Exchange2", NewAddress("sys", "host", 1))
-		pid2 := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
 		op := func() {
@@ -124,7 +127,8 @@ func TestReceiveContext(t *testing.T) {
 		// create actor1
 		actor1 := &Exchanger{}
 		actorPath1 := NewPath("Exchange1", NewAddress("sys", "host", 1))
-		pid1 := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create an instance of receive context
@@ -140,7 +144,8 @@ func TestReceiveContext(t *testing.T) {
 		// create actor2
 		actor2 := &Exchanger{}
 		actorPath2 := NewPath("Exchange2", NewAddress("sys", "host", 1))
-		pid2 := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
 		// wait a while and shutdown actor2
@@ -166,7 +171,8 @@ func TestReceiveContext(t *testing.T) {
 		// create actor1
 		actor1 := &Exchanger{}
 		actorPath1 := NewPath("Exchange1", NewAddress("sys", "host", 1))
-		pid1 := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create an instance of receive context
@@ -182,7 +188,8 @@ func TestReceiveContext(t *testing.T) {
 		// create actor2
 		actor2 := &Exchanger{}
 		actorPath2 := NewPath("Exchange2", NewAddress("sys", "host", 1))
-		pid2 := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
 		reply := context.Ask(pid2, new(testpb.TestReply))
@@ -205,7 +212,8 @@ func TestReceiveContext(t *testing.T) {
 		// create actor1
 		actor1 := &Exchanger{}
 		actorPath1 := NewPath("Exchange1", NewAddress("sys", "host", 1))
-		pid1 := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create an instance of receive context
@@ -221,7 +229,8 @@ func TestReceiveContext(t *testing.T) {
 		// create actor2
 		actor2 := &Exchanger{}
 		actorPath2 := NewPath("Exchange2", NewAddress("sys", "host", 1))
-		pid2 := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
 		// wait a while and shutdown actor2
@@ -261,17 +270,19 @@ func TestReceiveContext(t *testing.T) {
 
 		// create an exchanger two
 		actorName2 := "Exchange2"
-		actorRef2 := sys.Spawn(ctx, actorName2, &Exchanger{})
+		actorRef2, err := sys.Spawn(ctx, actorName2, &Exchanger{})
+		require.NoError(t, err)
 		assert.NotNil(t, actorRef2)
 
 		// create actor1
 		actor1 := &Exchanger{}
 		actorPath1 := NewPath("Exchange1", NewAddress("sys", "host", 1))
-		pid1 := newPID(ctx,
+		pid1, err := newPID(ctx,
 			actorPath1,
 			actor1,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger))
+		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create an instance of receive context
@@ -328,11 +339,13 @@ func TestReceiveContext(t *testing.T) {
 		// create actor1
 		actor1 := &Exchanger{}
 		actorPath1 := NewPath("Exchange1", NewAddress("sys", "host", 1))
-		pid1 := newPID(ctx,
+		pid1, err := newPID(ctx,
 			actorPath1,
 			actor1,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create an instance of receive context
@@ -387,17 +400,21 @@ func TestReceiveContext(t *testing.T) {
 
 		// create an exchanger two
 		actorName2 := "Exchange2"
-		actorRef2 := sys.Spawn(ctx, actorName2, &Exchanger{})
+		actorRef2, err := sys.Spawn(ctx, actorName2, &Exchanger{})
+
+		require.NoError(t, err)
 		assert.NotNil(t, actorRef2)
 
 		// create actor1
 		actor1 := &Exchanger{}
 		actorPath1 := NewPath("Exchange1", NewAddress("sys", "host", 1))
-		pid1 := newPID(ctx,
+		pid1, err := newPID(ctx,
 			actorPath1,
 			actor1,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create an instance of receive context
@@ -453,11 +470,13 @@ func TestReceiveContext(t *testing.T) {
 		// create actor1
 		actor1 := &Exchanger{}
 		actorPath1 := NewPath("Exchange1", NewAddress("sys", "host", 1))
-		pid1 := newPID(ctx,
+		pid1, err := newPID(ctx,
 			actorPath1,
 			actor1,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create an instance of receive context
@@ -487,7 +506,7 @@ func TestReceiveContext(t *testing.T) {
 			assert.NoError(t, sys.Stop(ctx))
 		})
 	})
-	t.Run("With panic RemoteLookup", func(t *testing.T) {
+	t.Run("With address not found RemoteLookup", func(t *testing.T) {
 		// create the context
 		ctx := context.TODO()
 		// define the logger to use
@@ -516,11 +535,13 @@ func TestReceiveContext(t *testing.T) {
 		// create actor1
 		actor1 := &Exchanger{}
 		actorPath1 := NewPath("Exchange1", NewAddress("sys", "host", 1))
-		pid1 := newPID(ctx,
+		pid1, err := newPID(ctx,
 			actorPath1,
 			actor1,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create an instance of receive context
@@ -533,10 +554,7 @@ func TestReceiveContext(t *testing.T) {
 			isAsyncMessage: true,
 		}
 
-		// send the message to t exchanger actor one using remote messaging
-		assert.Panics(t, func() {
-			context.RemoteLookup(host, remotingPort, actorName2)
-		})
+		require.Nil(t, context.RemoteLookup(host, remotingPort, actorName2))
 
 		time.Sleep(time.Second)
 
@@ -556,7 +574,9 @@ func TestReceiveContext(t *testing.T) {
 		// create actor1
 		actor1 := &Exchanger{}
 		actorPath1 := NewPath("Exchange1", NewAddress("sys", "host", 1))
-		pid1 := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+
+		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create an instance of receive context
@@ -578,11 +598,13 @@ func TestReceiveContext(t *testing.T) {
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx, actorPath,
+		parent, err := newPID(ctx, actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// create an instance of receive context
@@ -614,11 +636,13 @@ func TestReceiveContext(t *testing.T) {
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx, actorPath,
+		parent, err := newPID(ctx, actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// create an instance of receive context
@@ -644,11 +668,13 @@ func TestReceiveContext(t *testing.T) {
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx, actorPath,
+		parent, err := newPID(ctx, actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// create an instance of receive context
@@ -683,11 +709,13 @@ func TestReceiveContext(t *testing.T) {
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx, actorPath,
+		parent, err := newPID(ctx, actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// create an instance of receive context
@@ -722,11 +750,13 @@ func TestReceiveContext(t *testing.T) {
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx, actorPath,
+		parent, err := newPID(ctx, actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// create an instance of receive context
@@ -761,11 +791,13 @@ func TestReceiveContext(t *testing.T) {
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx, actorPath,
+		parent, err := newPID(ctx, actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// create an instance of receive context
@@ -802,11 +834,13 @@ func TestReceiveContext(t *testing.T) {
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx, actorPath,
+		parent, err := newPID(ctx, actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// create an instance of receive context
@@ -834,11 +868,13 @@ func TestReceiveContext(t *testing.T) {
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx, actorPath,
+		parent, err := newPID(ctx, actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// create an instance of receive context
@@ -872,11 +908,13 @@ func TestReceiveContext(t *testing.T) {
 		actorPath := NewPath("parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx, actorPath,
+		parent, err := newPID(ctx, actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// create an instance of receive context
@@ -891,12 +929,14 @@ func TestReceiveContext(t *testing.T) {
 
 		// create the child actor
 		childPath := NewPath("child", NewAddress("sys", "host", 1))
-		child := newPID(ctx, childPath,
+		child, err := newPID(ctx, childPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
 
+		require.NoError(t, err)
+
 		// stop the child actor
 		assert.Panics(t, func() {
 			context.Stop(child)
@@ -907,4 +947,47 @@ func TestReceiveContext(t *testing.T) {
 			assert.NoError(t, child.Shutdown(ctx))
 		})
 	})
+	t.Run("With Stop when child is already stopped", func(t *testing.T) {
+		ctx := context.TODO()
+		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
+
+		// create the parent actor
+		parent, err := newPID(ctx, actorPath,
+			NewMonitor(),
+			withInitMaxRetries(1),
+			withCustomLogger(log.DiscardLogger),
+			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
+		assert.NotNil(t, parent)
+
+		// create an instance of receive context
+		context := &receiveContext{
+			ctx:            ctx,
+			message:        new(testpb.TestSend),
+			sender:         NoSender,
+			recipient:      parent,
+			mu:             sync.Mutex{},
+			isAsyncMessage: true,
+		}
+
+		// create the child actor
+		name := "monitored"
+		child := context.Spawn(name, NewMonitored())
+		assert.NotNil(t, child)
+		assert.Len(t, context.Children(), 1)
+
+		// stop the child
+		assert.NoError(t, child.Shutdown(ctx))
+		// stop the child actor
+		assert.Panics(t, func() {
+			context.Stop(child)
+		})
+
+		time.Sleep(time.Second)
+		assert.Empty(t, context.Children())
+		t.Cleanup(func() {
+			context.Shutdown()
+		})
+	})
 }
diff --git a/actors/pid_test.go b/actors/pid_test.go
index 7627bf8..c096093 100644
--- a/actors/pid_test.go
+++ b/actors/pid_test.go
@@ -30,7 +30,7 @@ func TestActorReceive(t *testing.T) {
 	actorPath := NewPath("Test", NewAddress("sys", "host", 1))
 
 	// create the actor ref
-	pid := newPID(
+	pid, err := newPID(
 		ctx,
 		actorPath,
 		NewTester(),
@@ -38,6 +38,7 @@ func TestActorReceive(t *testing.T) {
 		withCustomLogger(log.DefaultLogger),
 		withSendReplyTimeout(receivingTimeout))
 
+	require.NoError(t, err)
 	assert.NotNil(t, pid)
 	// let us send 10 public to the actor
 	count := 10
@@ -55,7 +56,7 @@ func TestActorReceive(t *testing.T) {
 	}
 	assert.EqualValues(t, count, pid.ReceivedCount(ctx))
 	// stop the actor
-	err := pid.Shutdown(ctx)
+	err = pid.Shutdown(ctx)
 	assert.NoError(t, err)
 }
 func TestActorWithPassivation(t *testing.T) {
@@ -69,7 +70,8 @@ func TestActorWithPassivation(t *testing.T) {
 
 	// create the actor path
 	actorPath := NewPath("Test", NewAddress("sys", "host", 1))
-	pid := newPID(ctx, actorPath, NewTester(), opts...)
+	pid, err := newPID(ctx, actorPath, NewTester(), opts...)
+	require.NoError(t, err)
 	assert.NotNil(t, pid)
 
 	// let us sleep for some time to make the actor idle
@@ -82,7 +84,7 @@ func TestActorWithPassivation(t *testing.T) {
 	// block until timer is up
 	wg.Wait()
 	// let us send a message to the actor
-	err := Tell(ctx, pid, new(testpb.TestSend))
+	err = Tell(ctx, pid, new(testpb.TestSend))
 	assert.Error(t, err)
 	assert.EqualError(t, err, ErrDead.Error())
 }
@@ -97,7 +99,9 @@ func TestActorWithReply(t *testing.T) {
 
 		// create the actor path
 		actorPath := NewPath("Test", NewAddress("sys", "host", 1))
-		pid := newPID(ctx, actorPath, NewTester(), opts...)
+		pid, err := newPID(ctx, actorPath, NewTester(), opts...)
+
+		require.NoError(t, err)
 		assert.NotNil(t, pid)
 
 		actual, err := Ask(ctx, pid, new(testpb.TestReply), receivingTimeout)
@@ -119,7 +123,9 @@ func TestActorWithReply(t *testing.T) {
 
 		// create the actor path
 		actorPath := NewPath("Test", NewAddress("sys", "host", 1))
-		pid := newPID(ctx, actorPath, NewTester(), opts...)
+		pid, err := newPID(ctx, actorPath, NewTester(), opts...)
+
+		require.NoError(t, err)
 		assert.NotNil(t, pid)
 
 		actual, err := Ask(ctx, pid, new(testpb.TestSend), receivingTimeout)
@@ -140,11 +146,13 @@ func TestActorWithReply(t *testing.T) {
 
 		// create the actor path
 		actorPath := NewPath("Test", NewAddress("sys", "host", 1))
-		pid := newPID(ctx, actorPath, NewTester(), opts...)
+		pid, err := newPID(ctx, actorPath, NewTester(), opts...)
+
+		require.NoError(t, err)
 		assert.NotNil(t, pid)
 
 		// stop the actor
-		err := pid.Shutdown(ctx)
+		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
 
 		actual, err := Ask(ctx, pid, new(testpb.TestReply), receivingTimeout)
@@ -164,15 +172,17 @@ func TestActorRestart(t *testing.T) {
 		// create the actor path
 		actorPath := NewPath("Test", NewAddress("sys", "host", 1))
 		// create the actor ref
-		pid := newPID(ctx, actorPath, actor,
+		pid, err := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withPassivationAfter(10*time.Second),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, pid)
 
 		// stop the actor
-		err := pid.Shutdown(ctx)
+		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
 
 		time.Sleep(time.Second)
@@ -207,11 +217,13 @@ func TestActorRestart(t *testing.T) {
 		actorPath := NewPath("Test", NewAddress("sys", "host", 1))
 
 		// create the actor ref
-		pid := newPID(ctx, actorPath, actor,
+		pid, err := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withPassivationAfter(passivateAfter),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, pid)
 		// let us send 10 public to the actor
 		count := 10
@@ -222,7 +234,7 @@ func TestActorRestart(t *testing.T) {
 		assert.EqualValues(t, count, pid.ReceivedCount(ctx))
 
 		// restart the actor
-		err := pid.Restart(ctx)
+		err = pid.Restart(ctx)
 		assert.NoError(t, err)
 		assert.True(t, pid.IsRunning())
 		// let us send 10 public to the actor
@@ -235,6 +247,12 @@ func TestActorRestart(t *testing.T) {
 		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
 	})
+	t.Run("noSender cannot be restarted", func(t *testing.T) {
+		pid := &pid{}
+		err := pid.Restart(context.TODO())
+		assert.Error(t, err)
+		assert.EqualError(t, err, ErrUndefinedActor.Error())
+	})
 }
 func TestActorWithSupervisorStrategy(t *testing.T) {
 	t.Run("With happy path", func(t *testing.T) {
@@ -244,11 +262,13 @@ func TestActorWithSupervisorStrategy(t *testing.T) {
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx, actorPath,
+		parent, err := newPID(ctx, actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// create the child actor
@@ -277,13 +297,15 @@ func TestActorWithSupervisorStrategy(t *testing.T) {
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx,
+		parent, err := newPID(ctx,
 			actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withPassivationDisabled(),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// create the child actor
@@ -316,7 +338,7 @@ func TestActorWithSupervisorStrategy(t *testing.T) {
 		// create the actor path
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 		// create the parent actor
-		parent := newPID(ctx,
+		parent, err := newPID(ctx,
 			actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
@@ -324,6 +346,8 @@ func TestActorWithSupervisorStrategy(t *testing.T) {
 			withPassivationDisabled(),
 			withSupervisorStrategy(RestartDirective),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// create the child actor
@@ -353,13 +377,15 @@ func TestActorWithSupervisorStrategy(t *testing.T) {
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx,
+		parent, err := newPID(ctx,
 			actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withPassivationDisabled(),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// this is for the sake of the test
@@ -398,15 +424,18 @@ func TestActorToActor(t *testing.T) {
 		// create the actor path
 		actor1 := &Exchanger{}
 		actorPath1 := NewPath("Exchange1", NewAddress("sys", "host", 1))
-		pid1 := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+
+		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		actor2 := &Exchanger{}
 		actorPath2 := NewPath("Exchange2", NewAddress("sys", "host", 1))
-		pid2 := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
-		err := pid1.Tell(ctx, pid2, new(testpb.TestSend))
+		err = pid1.Tell(ctx, pid2, new(testpb.TestSend))
 		require.NoError(t, err)
 
 		// send an ask
@@ -444,12 +473,15 @@ func TestActorToActor(t *testing.T) {
 		// create the actor path
 		actor1 := &Exchanger{}
 		actorPath1 := NewPath("Exchange1", NewAddress("sys", "host", 1))
-		pid1 := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+
+		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		actor2 := &Exchanger{}
 		actorPath2 := NewPath("Exchange2", NewAddress("sys", "host", 1))
-		pid2 := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
 		time.Sleep(time.Second)
@@ -479,12 +511,14 @@ func TestActorToActor(t *testing.T) {
 		// create the actor path
 		actor1 := &Exchanger{}
 		actorPath1 := NewPath("Exchange1", NewAddress("sys", "host", 1))
-		pid1 := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		actor2 := &Exchanger{}
 		actorPath2 := NewPath("Exchange2", NewAddress("sys", "host", 1))
-		pid2 := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
 		time.Sleep(time.Second)
@@ -492,7 +526,7 @@ func TestActorToActor(t *testing.T) {
 		assert.NoError(t, pid2.Shutdown(ctx))
 
 		// send an ask
-		err := pid1.Tell(ctx, pid2, new(testpb.TestReply))
+		err = pid1.Tell(ctx, pid2, new(testpb.TestReply))
 		require.Error(t, err)
 		require.EqualError(t, err, ErrDead.Error())
 
@@ -528,12 +562,14 @@ func TestActorRemoting(t *testing.T) {
 
 	// create an exchanger one
 	actorName1 := "Exchange1"
-	actorRef1 := sys.Spawn(ctx, actorName1, &Exchanger{})
+	actorRef1, err := sys.Spawn(ctx, actorName1, &Exchanger{})
+	require.NoError(t, err)
 	assert.NotNil(t, actorRef1)
 
 	// create an exchanger two
 	actorName2 := "Exchange2"
-	actorRef2 := sys.Spawn(ctx, actorName2, &Exchanger{})
+	actorRef2, err := sys.Spawn(ctx, actorName2, &Exchanger{})
+	require.NoError(t, err)
 	assert.NotNil(t, actorRef2)
 
 	// get the address of the exchanger actor one
@@ -572,7 +608,7 @@ func TestActorHandle(t *testing.T) {
 	actorPath := NewPath("Test", NewAddress("sys", "host", 1))
 
 	// create the actor ref
-	pid := newPID(
+	pid, err := newPID(
 		ctx,
 		actorPath,
 		&Exchanger{},
@@ -580,6 +616,7 @@ func TestActorHandle(t *testing.T) {
 		withCustomLogger(log.DefaultLogger),
 		withSendReplyTimeout(receivingTimeout))
 
+	require.NoError(t, err)
 	assert.NotNil(t, pid)
 	actorHandle := pid.ActorHandle()
 	assert.IsType(t, &Exchanger{}, actorHandle)
@@ -587,7 +624,7 @@ func TestActorHandle(t *testing.T) {
 	_, ok := p.(Actor)
 	assert.True(t, ok)
 	// stop the actor
-	err := pid.Shutdown(ctx)
+	err = pid.Shutdown(ctx)
 	assert.NoError(t, err)
 }
 func TestPIDActorSystem(t *testing.T) {
@@ -596,19 +633,19 @@ func TestPIDActorSystem(t *testing.T) {
 	actorPath := NewPath("Test", NewAddress("sys", "host", 1))
 
 	// create the actor ref
-	pid := newPID(
+	pid, err := newPID(
 		ctx,
 		actorPath,
 		&Exchanger{},
 		withInitMaxRetries(1),
 		withCustomLogger(log.DefaultLogger),
 		withSendReplyTimeout(receivingTimeout))
-
+	require.NoError(t, err)
 	assert.NotNil(t, pid)
 	sys := pid.ActorSystem()
 	assert.Nil(t, sys)
 	// stop the actor
-	err := pid.Shutdown(ctx)
+	err = pid.Shutdown(ctx)
 	assert.NoError(t, err)
 }
 func TestSpawnChild(t *testing.T) {
@@ -619,11 +656,13 @@ func TestSpawnChild(t *testing.T) {
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx, actorPath,
+		parent, err := newPID(ctx, actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// create the child actor
@@ -657,11 +696,13 @@ func TestSpawnChild(t *testing.T) {
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx, actorPath,
+		parent, err := newPID(ctx, actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		// create the child actor
@@ -692,16 +733,18 @@ func TestSpawnChild(t *testing.T) {
 		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
 
 		// create the parent actor
-		parent := newPID(ctx, actorPath,
+		parent, err := newPID(ctx, actorPath,
 			NewMonitor(),
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
 			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
 		time.Sleep(100 * time.Millisecond)
 		//stop the actor
-		err := parent.Shutdown(ctx)
+		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
 
 		// create the child actor
@@ -710,6 +753,32 @@ func TestSpawnChild(t *testing.T) {
 		assert.EqualError(t, err, ErrDead.Error())
 		assert.Nil(t, child)
 	})
+	t.Run("With failed init", func(t *testing.T) {
+		// create a test context
+		ctx := context.TODO()
+		// create the actor path
+		actorPath := NewPath("Parent", NewAddress("sys", "host", 1))
+
+		// create the parent actor
+		parent, err := newPID(ctx, actorPath,
+			NewMonitor(),
+			withInitMaxRetries(1),
+			withCustomLogger(log.DiscardLogger),
+			withSendReplyTimeout(receivingTimeout))
+
+		require.NoError(t, err)
+		assert.NotNil(t, parent)
+
+		// create the child actor
+		child, err := parent.SpawnChild(ctx, "SpawnChild", &InitTester{})
+		assert.Error(t, err)
+		assert.Nil(t, child)
+
+		assert.Len(t, parent.Children(ctx), 0)
+		//stop the actor
+		err = parent.Shutdown(ctx)
+		assert.NoError(t, err)
+	})
 }
 func TestPoisonPill(t *testing.T) {
 	ctx := context.TODO()
@@ -718,21 +787,132 @@ func TestPoisonPill(t *testing.T) {
 	actorPath := NewPath("Test", NewAddress("sys", "host", 1))
 
 	// create the actor ref
-	pid := newPID(
+	pid, err := newPID(
 		ctx,
 		actorPath,
 		NewTester(),
 		withInitMaxRetries(1),
 		withCustomLogger(log.DefaultLogger),
 		withSendReplyTimeout(receivingTimeout))
+
+	require.NoError(t, err)
 	assert.NotNil(t, pid)
 
 	assert.True(t, pid.IsRunning())
 	// send a poison pill to the actor
-	err := Tell(ctx, pid, new(messagespb.PoisonPill))
+	err = Tell(ctx, pid, new(messagespb.PoisonPill))
 	assert.NoError(t, err)
 
 	// wait for the graceful shutdown
 	time.Sleep(time.Second)
 	assert.False(t, pid.IsRunning())
 }
+func TestRemoteLookup(t *testing.T) {
+	t.Run("With actor address not found", func(t *testing.T) {
+		// create the context
+		ctx := context.TODO()
+		// define the logger to use
+		logger := log.New(log.DebugLevel, os.Stdout)
+		// generate the remoting port
+		nodePorts := dynaport.Get(1)
+		remotingPort := nodePorts[0]
+		host := "localhost"
+
+		// create the actor system
+		sys, err := NewActorSystem("test",
+			WithLogger(logger),
+			WithPassivationDisabled(),
+			WithRemoting(host, int32(remotingPort)),
+		)
+		// assert there are no error
+		require.NoError(t, err)
+
+		// start the actor system
+		err = sys.Start(ctx)
+		assert.NoError(t, err)
+
+		// create an exchanger 1
+		actorName1 := "Exchange1"
+		actorRef1, err := sys.Spawn(ctx, actorName1, &Exchanger{})
+
+		require.NoError(t, err)
+		assert.NotNil(t, actorRef1)
+
+		// let us lookup actor two
+		actorName2 := "Exchange2"
+		addr, err := actorRef1.RemoteLookup(ctx, host, remotingPort, actorName2)
+		require.NoError(t, err)
+		require.Nil(t, addr)
+
+		t.Cleanup(func() {
+			assert.NoError(t, sys.Stop(ctx))
+		})
+	})
+	t.Run("With remoting not enabled", func(t *testing.T) {
+		// create the context
+		ctx := context.TODO()
+		// define the logger to use
+		logger := log.New(log.DebugLevel, os.Stdout)
+		// generate the remoting port
+		nodePorts := dynaport.Get(1)
+		remotingPort := nodePorts[0]
+		host := "localhost"
+
+		// create the actor system
+		sys, err := NewActorSystem("test",
+			WithLogger(logger),
+			WithPassivationDisabled())
+		// assert there are no error
+		require.NoError(t, err)
+
+		// start the actor system
+		err = sys.Start(ctx)
+		assert.NoError(t, err)
+
+		// create an exchanger 1
+		actorName1 := "Exchange1"
+		actorRef1, err := sys.Spawn(ctx, actorName1, &Exchanger{})
+
+		require.NoError(t, err)
+		assert.NotNil(t, actorRef1)
+
+		// let us lookup actor two
+		actorName2 := "Exchange2"
+		addr, err := actorRef1.RemoteLookup(ctx, host, remotingPort, actorName2)
+		require.Error(t, err)
+		require.Nil(t, addr)
+
+		t.Cleanup(func() {
+			assert.NoError(t, sys.Stop(ctx))
+		})
+	})
+}
+func TestFailedInit(t *testing.T) {
+	// create the context
+	ctx := context.TODO()
+	// define the logger to use
+	logger := log.New(log.DebugLevel, os.Stdout)
+
+	// create the actor system
+	sys, err := NewActorSystem("test",
+		WithLogger(logger),
+		WithActorInitMaxRetries(1),
+		WithPassivationDisabled())
+	// assert there are no error
+	require.NoError(t, err)
+
+	// start the actor system
+	err = sys.Start(ctx)
+	assert.NoError(t, err)
+
+	// create an exchanger 1
+	actorName1 := "Exchange1"
+	pid, err := sys.Spawn(ctx, actorName1, &InitTester{})
+	require.Error(t, err)
+	require.EqualError(t, err, "failed to initialize: failed")
+	require.Nil(t, pid)
+
+	t.Cleanup(func() {
+		assert.NoError(t, sys.Stop(ctx))
+	})
+}
diff --git a/actors/stash_test.go b/actors/stash_test.go
index 787f2f3..e57ad06 100644
--- a/actors/stash_test.go
+++ b/actors/stash_test.go
@@ -24,14 +24,15 @@ func TestStash(t *testing.T) {
 		// create the actor path
 		actor := &Stasher{}
 		actorPath := NewPath("Stasher", NewAddress("sys", "host", 1))
-		pid := newPID(ctx, actorPath, actor, opts...)
+		pid, err := newPID(ctx, actorPath, actor, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid)
 
 		// wait for the actor to properly start
 		time.Sleep(time.Second)
 
 		// send a stash message to the actor
-		err := Tell(ctx, pid, new(testpb.TestStash))
+		err = Tell(ctx, pid, new(testpb.TestStash))
 		require.NoError(t, err)
 
 		// add some pause here due to async calls
@@ -91,13 +92,14 @@ func TestStash(t *testing.T) {
 		// create the actor path
 		actor := &Stasher{}
 		actorPath := NewPath("Stasher", NewAddress("sys", "host", 1))
-		pid := newPID(ctx, actorPath, actor, opts...)
+		pid, err := newPID(ctx, actorPath, actor, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid)
 
 		// wait for the actor to properly start
 		time.Sleep(5 * time.Millisecond)
 
-		err := pid.stash(new(receiveContext))
+		err = pid.stash(new(receiveContext))
 		assert.Error(t, err)
 		assert.EqualError(t, err, ErrStashBufferNotSet.Error())
 
@@ -115,13 +117,14 @@ func TestStash(t *testing.T) {
 		// create the actor path
 		actor := &Stasher{}
 		actorPath := NewPath("Stasher", NewAddress("sys", "host", 1))
-		pid := newPID(ctx, actorPath, actor, opts...)
+		pid, err := newPID(ctx, actorPath, actor, opts...)
+		require.NoError(t, err)
 		require.NotNil(t, pid)
 
 		// wait for the actor to properly start
 		time.Sleep(5 * time.Millisecond)
 
-		err := pid.unstash()
+		err = pid.unstash()
 		assert.Error(t, err)
 		assert.EqualError(t, err, ErrStashBufferNotSet.Error())
 
diff --git a/bench/bench_test.go b/bench/bench_test.go
index ca16158..f662a5e 100644
--- a/bench/bench_test.go
+++ b/bench/bench_test.go
@@ -52,7 +52,7 @@ func BenchmarkActor(b *testing.B) {
 		actor := &Benchmarker{}
 
 		// create the actor ref
-		pid := actorSystem.Spawn(ctx, "test", actor)
+		pid, _ := actorSystem.Spawn(ctx, "test", actor)
 
 		b.ResetTimer() // Reset the benchmark timer
 		b.RunParallel(func(pb *testing.PB) {
@@ -82,7 +82,7 @@ func BenchmarkActor(b *testing.B) {
 		actor := &Benchmarker{}
 
 		// create the actor ref
-		pid := actorSystem.Spawn(ctx, "test", actor)
+		pid, _ := actorSystem.Spawn(ctx, "test", actor)
 
 		b.ResetTimer() // Reset the benchmark timer
 		b.RunParallel(func(pb *testing.PB) {