{"record":{"id":"87f05dd4686e86f1","repo":"temporalio/temporal","slug":"empty-operation-token","errorCode":null,"errorMessage":"empty operation token","messagePattern":"empty operation token","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/nexus/nexusrpc/client.go","lineNumber":43,"sourceCode":"\t// A function for making HTTP requests.\n\t// Defaults to [http.DefaultClient.Do].\n\tHTTPCaller func(*http.Request) (*http.Response, error)\n\t// A [Serializer] to customize client serialization behavior.\n\t// By default the client handles JSONables, byte slices, and nil.\n\tSerializer nexus.Serializer\n\t// A [FailureConverter] to convert a [Failure] instance to and from an [error]. Defaults to\n\t// [DefaultFailureConverter].\n\tFailureConverter FailureConverter\n}\n\n// User-Agent header set on HTTP requests.\nconst userAgent = \"temporalio/server\"\n\nconst headerUserAgent = \"User-Agent\"\n\nvar errEmptyOperationName = errors.New(\"empty operation name\")\n\nvar errEmptyOperationToken = errors.New(\"empty operation token\")\n\n// UnexpectedResponseError indicates a client encountered something unexpected in the server's response.\ntype UnexpectedResponseError struct {\n\t// Error message.\n\tMessage string\n\t// Optional failure that may have been emedded in the response.\n\tFailure *nexus.Failure\n\t// Additional transport specific details.\n\t// For HTTP, this would include the HTTP response. The response body will have already been read into memory and\n\t// does not need to be closed.\n\tDetails any\n}\n\n// Error implements the error interface.\nfunc (e *UnexpectedResponseError) Error() string {\n\treturn e.Message\n}\n","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/nexus/nexusrpc/client.go#L25-L61","documentation":"errEmptyOperationToken is a sentinel in common/nexus/nexusrpc/client.go indicating NewOperationHandle received an empty operation token. The token identifies a started asynchronous operation instance; without it the handle cannot address the operation, so it is rejected at construction time.","triggerScenarios":"Calling NewOperationHandle with operationToken == \"\", e.g. a token that was never captured from a StartOperation response, or one lost through an empty JSON field when persisting the handle.","commonSituations":"Storing operation handles and reading back an empty token field; passing through unset variables from a StartOperation result; test coverage of failure conditions (TestNewHandleFailureConditions).","solutions":["Ensure the token returned from a successful StartOperation call is propagated to NewOperationHandle","Persist and restore the token (it is often base64-encoded) without dropping it","Guard with errors.Is(err, nexusrpc.ErrEmptyOperationToken) to surface the cause"],"exampleFix":"// before\nhandle, _ := client.NewOperationHandle(ctx, op, savedToken) // savedToken was \"\"\n// after\nif savedToken == \"\" {\n    return nil, fmt.Errorf(\"operation token missing from stored handle\")\n}\nhandle, err := client.NewOperationHandle(ctx, op, savedToken)","handlingStrategy":"validation","validationCode":"func checkHandleArgs(operationName, token string) error {\n    if token == \"\" { return errors.New(\"operation token required\") }\n    return nil\n}","typeGuard":"func hasOperationToken(token string) bool { return token != \"\" }","tryCatchPattern":"handle, err := client.NewOperationHandle(ctx, opName, token)\nif errors.Is(err, nexusrpc.ErrEmptyOperationToken) {\n    return fmt.Errorf(\"operation token missing: was the operation started and its token persisted?\")\n}","preventionTips":["Always capture the token from the StartOperation result immediately and persist it atomically","Use nullable/explicit fields when serializing handles so empty tokens are detectable","Never pass through zero-valued token variables; check before use"],"tags":["nexus","client","validation"],"backgroundTag":"empty-required-field","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}