{"record":{"id":"575b1ee6e60cd781","repo":"dapr/dapr","slug":"received-job-but-app-channel-not-initialized","errorCode":null,"errorMessage":"received job, but app channel not initialized","messagePattern":"received job, but app channel not initialized","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/runtime/scheduler/internal/cluster/streamer.go","lineNumber":198,"sourceCode":"\t\t\t\treturn schedulerv1pb.WatchJobsRequestResultStatus_SUCCESS\n\t\t\t}\n\t\t}\n\n\t\tlog.Errorf(\"failed to invoke scheduled actor reminder named: %s due to: %s\", job.GetName(), err)\n\n\t\treturn schedulerv1pb.WatchJobsRequestResultStatus_FAILED\n\n\tdefault:\n\t\tlog.Errorf(\"Unknown job metadata type: %+v\", t)\n\t\treturn schedulerv1pb.WatchJobsRequestResultStatus_FAILED\n\t}\n}\n\n// invokeApp calls the local app with the given job data.\nfunc (s *streamer) invokeApp(ctx context.Context, job *schedulerv1pb.WatchJobsResponse) error {\n\tappChannel := s.channels.AppChannel()\n\tif appChannel == nil {\n\t\treturn errors.New(\"received job, but app channel not initialized\")\n\t}\n\n\tstart := time.Now()\n\n\tresponse, err := appChannel.TriggerJob(ctx, job.GetName(), job.GetData())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error returned from app channel while sending triggered job to app: %w\", err)\n\t}\n\n\tif response != nil {\n\t\tdefer response.Close()\n\t}\n\n\telapsedMs := diag.ElapsedSince(start)\n\t// TODO: standardize on the error code returned by both protocol channels,\n\t// converting HTTP status codes to gRPC codes\n\tstatusCode := response.Status().GetCode()\n\t// TODO: fix types","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/dapr/dapr/blob/74ad41702745709bb15fe2114ff693b8c59bc3cc/pkg/runtime/scheduler/internal/cluster/streamer.go#L180-L216","documentation":"Returned by the scheduler streamer's invokeApp when a job is delivered to the sidecar but the local app channel (the HTTP/gRPC connection from daprd to your application) is nil. The app channel is only created when Dapr knows how to reach the app (an app-port is configured and the connection was established); without it the job cannot be forwarded to user code, so the job is reported FAILED back to the scheduler.","triggerScenarios":"Running daprd without --app-port (or app-port empty in the spec) while the app subscribes to scheduled jobs; a gRPC-only app channel that failed to initialize; invoking a Job with a target that expects app delivery while the runtime has no app connection.","commonSituations":"Using the Jobs API from a sidecar that never exposes an HTTP endpoint; actor/service invocation-only workloads that add scheduling without an app port; app channel initialization failing silently at startup because the app was not listening yet.","solutions":["Configure the app port: annotate the deployment with dapr.io/app-port or pass --app-port so daprd can build the app channel.","Confirm the app is listening on that port and the protocol (--app-protocol http/grpc) matches the app server.","Check sidecar logs at startup for app channel creation errors and restart the pod so the channel is built after the app is up.","If the workload needs no app code (pure actor reminders handled by actor runtime), verify the job type/subscription mode instead of expecting app delivery."],"exampleFix":"# before: deployment without app port\nmetadata:\n  annotations:\n    dapr.io/enabled: \"true\"\n\n# after: give daprd a port to reach the app\nmetadata:\n  annotations:\n    dapr.io/enabled: \"true\"\n    dapr.io/app-port: \"8080\"\n    dapr.io/app-protocol: \"http\"","handlingStrategy":"validation","validationCode":"# Before deploying Jobs subscribers, assert the app channel exists\nkubectl get deploy myapp -o jsonpath='{.spec.template.metadata.annotations.dapr\\.io/app-port}'\n# non-empty output means the sidecar will build an app channel","typeGuard":null,"tryCatchPattern":"err := streamer.InvokeJob(ctx, job)\nif err != nil && strings.Contains(err.Error(), \"app channel not initialized\") {\n    // configuration problem, not transient: surface to operator\n    return fmt.Errorf(\"jobs require app-port on the sidecar: %w\", err)\n}","preventionTips":["Always set dapr.io/app-port on deployments that subscribe to Jobs.","Add a startup probe on the app so the channel initializes after the app listens.","CI-check manifests for app-port when job subscriptions exist."],"tags":["jobs","scheduler","app-channel","configuration","go"],"backgroundTag":null,"analyzedSha":"74ad41702745709bb15fe2114ff693b8c59bc3cc","analyzedAt":"2026-08-16T04:22:26.543Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}