wavetermdev/waveterm · error

no jobauthtoken in authenticatejobmanager message

Error message

no jobauthtoken in authenticatejobmanager message

What it means

The AuthenticateJobManagerVerify RPC payload must include the JobAuthToken secret to compare against the stored job record. An empty JobAuthToken can never match, so the command rejects it up front before touching the database.

Source

Thrown at pkg/wshutil/wshrouter_controlimpl.go:226

		return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("no routeid in token response")
	}
	log.Printf("wshrouter authenticate-token success linkid=%d routeid=%q", linkId, rtnData.RouteId)
	impl.Router.trustLink(linkId, LinkKind_Leaf)
	impl.Router.bindRoute(linkId, rtnData.RouteId, true)

	return rtnData, nil
}

func (impl *WshRouterControlImpl) AuthenticateJobManagerVerifyCommand(ctx context.Context, data wshrpc.CommandAuthenticateJobManagerData) error {
	if !impl.Router.IsRootRouter() {
		return fmt.Errorf("authenticatejobmanagerverify can only be called on root router")
	}

	if data.JobId == "" {
		return fmt.Errorf("no jobid in authenticatejobmanager message")
	}
	if data.JobAuthToken == "" {
		return fmt.Errorf("no jobauthtoken in authenticatejobmanager message")
	}

	job, err := wstore.DBMustGet[*waveobj.Job](ctx, data.JobId)
	if err != nil {
		log.Printf("wshrouter authenticate-jobmanager-verify error jobid=%q: failed to get job: %v", data.JobId, err)
		return fmt.Errorf("failed to get job: %w", err)
	}

	if job.JobAuthToken != data.JobAuthToken {
		log.Printf("wshrouter authenticate-jobmanager-verify error jobid=%q: invalid jobauthtoken", data.JobId)
		return fmt.Errorf("invalid jobauthtoken")
	}

	log.Printf("wshrouter authenticate-jobmanager-verify success jobid=%q", data.JobId)
	return nil
}

func (impl *WshRouterControlImpl) AuthenticateJobManagerCommand(ctx context.Context, data wshrpc.CommandAuthenticateJobManagerData) error {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Populate data.JobAuthToken from the job's stored secret before calling the RPC.
  2. Verify the source of the token (config/env/job record) is actually returning a value.
  3. Validate the payload before sending the RPC to fail fast.
  4. Check serialization so the jobauthtoken field is not dropped.

Example fix

// before
_, err := wshRpc.SendRpcRequest(wshrpc.Command_AuthenticateJobManagerVerify, wshrpc.CommandAuthenticateJobManagerData{JobId: id}, opts)
// after
if data.JobAuthToken == "" {
    return fmt.Errorf("cannot verify job: JobAuthToken is empty")
}
_, err := wshRpc.SendRpcRequest(wshrpc.Command_AuthenticateJobManagerVerify, data, opts)
Defensive patterns

Strategy: validation

Validate before calling

if data.JobAuthToken == "" {
    return fmt.Errorf("JobAuthToken is required for job-manager verification")
}
// safe to call RPC

Type guard

func jobDataComplete(d wshrpc.CommandAuthenticateJobManagerData) bool {
    return d.JobId != "" && d.JobAuthToken != ""
}

Try / catch

err := verifyJobManager(ctx, data)
if err != nil && strings.Contains(err.Error(), "no jobauthtoken in authenticatejobmanager message") {
    return fmt.Errorf("caller bug: JobAuthToken was never loaded: %w", err)
}

Prevention

When it happens

Trigger: Sending Command_AuthenticateJobManagerVerify with CommandAuthenticateJobManagerData{JobAuthToken: ""} — token never loaded from the job record, zero-value struct, or the field was dropped in serialization.

Common situations: Client lost the job secret (e.g. reading from a different job record or a cleared cache); building the data struct partially; environment where the job manager hands off only the job id.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/257c7fff60e5e4f4. Report an issue: GitHub.