{"record":{"id":"1cf9c0d26704064c","repo":"dapr/dapr","slug":"remote-actor-moved","errorCode":null,"errorMessage":"remote actor moved","messagePattern":"remote actor moved","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/actors/router/router.go","lineNumber":200,"sourceCode":"func (r *router) callReminder(ctx context.Context, req *api.Reminder) error {\n\tlar, cctx, cancel, err := r.placement.LookupActor(ctx, &api.LookupActorRequest{\n\t\tActorType: req.ActorType,\n\t\tActorID:   req.ActorID,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif req.SkipLock || !lar.Local {\n\t\tcancel(nil)\n\t} else {\n\t\tdefer cancel(nil)\n\t\tctx = cctx\n\t}\n\n\tif !lar.Local {\n\t\tif req.IsRemote {\n\t\t\treturn backoff.Permanent(errors.New(\"remote actor moved\"))\n\t\t}\n\n\t\terr = r.callRemoteActorReminder(ctx, lar, req)\n\t\tstatus, ok := status.FromError(err)\n\t\tif ok && status.Code() == codes.Unavailable {\n\t\t\treturn backoff.Permanent(err)\n\t\t}\n\t\treturn err\n\t}\n\n\ttarget, err := r.table.GetOrCreate(req.ActorType, req.ActorID)\n\tif err != nil {\n\t\treturn backoff.Permanent(err)\n\t}\n\n\tif req.IsTimer {\n\t\terr = target.InvokeTimer(ctx, req)\n\t} else {","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/dapr/dapr/blob/74ad41702745709bb15fe2114ff693b8c59bc3cc/pkg/actors/router/router.go#L182-L218","documentation":"GenerateJWT persists the signing key by marshalling it to PKCS8 (x509.MarshalPKCS8PrivateKey) and PEM-encoding it. MarshalPKCS8 supports RSA, ECDSA, Ed25519, and X25519 keys; any other crypto.Signer type — notably custom signers or unsupported algorithms — yields 'failed to marshal JWT signing key'. As above, the in-repo caller passes a generated RSA key, so this guards against unsupported key types from external callers.","triggerScenarios":"OptionsJWT.JWTRootKey is a key type outside PKCS8's supported set (e.g., a DSA key or a wrapper Signer that is not one of the four supported concrete types).","commonSituations":"Forks adding algorithms like ML-DSA or custom HSM-backed signers; test harnesses passing mock signers.","solutions":["Use one of RSA/ECDSA/Ed25519 (or X25519) private keys as the JWT root key.","If you need another algorithm, serialize it yourself rather than via GenerateJWT.","Check the wrapped error to confirm the type rejection.","Keep the stored jwt.key as PKCS8 PEM so future loads round-trip."],"exampleFix":"// before: custom signer\ntype mySigner struct{ crypto.Signer }\nbundle.GenerateJWT(bundle.OptionsJWT{JWTRootKey: mySigner{...}})\n// after\nrsaKey, _ := rsa.GenerateKey(rand.Reader, 2048)\nbundle.GenerateJWT(bundle.OptionsJWT{JWTRootKey: rsaKey})","handlingStrategy":"type-guard","validationCode":"switch opts.JWTRootKey.(type) {\ncase *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey:\ndefault:\n\treturn fmt.Errorf(\"key type %T cannot be PKCS8-marshaled by GenerateJWT\", opts.JWTRootKey)\n}","typeGuard":"func isPKCS8Marshalable(k any) bool {\n\tswitch k.(type) {\n\tcase *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey, x25519.PrivateKey:\n\t\treturn true\n\t}\n\treturn false\n}","tryCatchPattern":"j, err := bundle.GenerateJWT(opts)\nif err != nil && strings.Contains(err.Error(), \"failed to marshal JWT signing key\") {\n\t// swap in a supported key type; custom Signers cannot be persisted here\n}","preventionTips":["Restrict JWT root keys to the four PKCS8-capable types.","For HSM/KMS signers, bypass GenerateJWT and manage persistence externally.","Round-trip test: marshal then ParsePKCS8PrivateKey in CI."],"tags":["dapr","sentry","jwt","pkcs8","cryptography"],"backgroundTag":null,"analyzedSha":"74ad41702745709bb15fe2114ff693b8c59bc3cc","analyzedAt":"2026-08-16T04:22:26.543Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}