dapr/dapr · error

received job, but app channel not initialized

Error message

received job, but app channel not initialized

What it means

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.

Source

Thrown at pkg/runtime/scheduler/internal/cluster/streamer.go:198

				return schedulerv1pb.WatchJobsRequestResultStatus_SUCCESS
			}
		}

		log.Errorf("failed to invoke scheduled actor reminder named: %s due to: %s", job.GetName(), err)

		return schedulerv1pb.WatchJobsRequestResultStatus_FAILED

	default:
		log.Errorf("Unknown job metadata type: %+v", t)
		return schedulerv1pb.WatchJobsRequestResultStatus_FAILED
	}
}

// invokeApp calls the local app with the given job data.
func (s *streamer) invokeApp(ctx context.Context, job *schedulerv1pb.WatchJobsResponse) error {
	appChannel := s.channels.AppChannel()
	if appChannel == nil {
		return errors.New("received job, but app channel not initialized")
	}

	start := time.Now()

	response, err := appChannel.TriggerJob(ctx, job.GetName(), job.GetData())
	if err != nil {
		return fmt.Errorf("error returned from app channel while sending triggered job to app: %w", err)
	}

	if response != nil {
		defer response.Close()
	}

	elapsedMs := diag.ElapsedSince(start)
	// TODO: standardize on the error code returned by both protocol channels,
	// converting HTTP status codes to gRPC codes
	statusCode := response.Status().GetCode()
	// TODO: fix types

View on GitHub (pinned to 74ad417027)

Solutions

  1. Configure the app port: annotate the deployment with dapr.io/app-port or pass --app-port so daprd can build the app channel.
  2. Confirm the app is listening on that port and the protocol (--app-protocol http/grpc) matches the app server.
  3. Check sidecar logs at startup for app channel creation errors and restart the pod so the channel is built after the app is up.
  4. 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.

Example fix

# before: deployment without app port
metadata:
  annotations:
    dapr.io/enabled: "true"

# after: give daprd a port to reach the app
metadata:
  annotations:
    dapr.io/enabled: "true"
    dapr.io/app-port: "8080"
    dapr.io/app-protocol: "http"
Defensive patterns

Strategy: validation

Validate before calling

# Before deploying Jobs subscribers, assert the app channel exists
kubectl get deploy myapp -o jsonpath='{.spec.template.metadata.annotations.dapr\.io/app-port}'
# non-empty output means the sidecar will build an app channel

Try / catch

err := streamer.InvokeJob(ctx, job)
if err != nil && strings.Contains(err.Error(), "app channel not initialized") {
    // configuration problem, not transient: surface to operator
    return fmt.Errorf("jobs require app-port on the sidecar: %w", err)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of dapr/dapr@74ad417027 (2026-08-16). Data as JSON: /api/errors/575b1ee6e60cd781. Report an issue: GitHub.