{"record":{"id":"64ca254f0a6041e4","repo":"temporalio/temporal","slug":"errinvalidoperationtoken","errorCode":"ErrInvalidOperationToken","errorMessage":"%w: length exceeds allowed limit (%d/%d)","messagePattern":"%w: length exceeds allowed limit \\((.+?)/(.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"chasm/lib/nexusoperation/operation_tasks.go","lineNumber":250,"sourceCode":"\t// This happens when we accept the ScheduleNexusOperation command when the endpoint is not found in the\n\t// registry as indicated by the EndpointNotFoundAlwaysNonRetryable dynamic config.\n\t// The config has been removed but we keep this check for backward compatibility.\n\tif args.endpointID == \"\" {\n\t\treturn nil, nexus.NewHandlerErrorf(nexus.HandlerErrorTypeNotFound, \"endpoint not registered\")\n\t}\n\treturn lookupEndpoint(ctx, h.endpointRegistry, ns.ID(), args.endpointID, args.endpointName)\n}\n\nfunc (h *operationInvocationTaskHandler) validateStartResult(\n\tns *namespace.Namespace,\n\tresult *nexusrpc.ClientStartOperationResponse[*commonpb.Payload],\n) error {\n\tif result == nil {\n\t\treturn nil\n\t}\n\ttokenLimit := h.config.MaxOperationTokenLength(ns.Name().String())\n\tif result.Pending != nil && len(result.Pending.Token) > tokenLimit {\n\t\treturn fmt.Errorf(\"%w: length exceeds allowed limit (%d/%d)\", ErrInvalidOperationToken, len(result.Pending.Token), tokenLimit)\n\t}\n\tif result.Successful != nil && result.Successful.Size() > h.config.PayloadSizeLimit(ns.Name().String()) {\n\t\treturn ErrResponseBodyTooLarge\n\t}\n\treturn nil\n}\n\ntype operationBackoffTaskHandler struct {\n\tchasm.PureTaskHandlerBase\n\tconfig *Config\n\n\tmetricsHandler metrics.Handler\n\tlogger         log.Logger\n}\n\nfunc newOperationBackoffTaskHandler(opts operationTaskHandlerOptions) *operationBackoffTaskHandler {\n\treturn &operationBackoffTaskHandler{\n\t\tconfig:         opts.Config,","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/chasm/lib/nexusoperation/operation_tasks.go#L232-L268","documentation":"When a Nexus operation handler returns a start result containing a pending-operations token, the token length must not exceed the configured MaxOperationTokenLength for the namespace. If it does, the result is rejected with ErrInvalidOperationToken wrapped with the actual and allowed lengths. This protects history from persisting oversized tokens.","triggerScenarios":"A Nexus operation handler returns nexus.OperationStartResult with result.Pending.Token longer than MaxOperationTokenLength (namespace-configured limit) — validateStartResult is called from Execute after the handler returns.","commonSituations":"A handler encodes too much state into the pending token (e.g. embedding large payloads/IDs); server operator lowers MaxOperationTokenLength below existing handler token sizes; namespace-specific config divergence between dev and prod.","solutions":["Reduce the token size returned by the handler: keep it a compact opaque reference and store state externally or in the operation component","Raise nexusoperation.pending token limit config (MaxOperationTokenLength) for the namespace if the current token size is legitimate","Log/compute len(token) in the handler and compare against the configured limit before returning","Check for accidental inclusion of large payloads (base64 blobs, full request bodies) in the token"],"exampleFix":"// before\nreturn &nexus.OperationStartResult{Pending: &nexus.OperationPending{Token: bigToken}}, nil\n// after\nif len(token) > maxTokenLen { token = compactToken(token) }\nreturn &nexus.OperationStartResult{Pending: &nexus.OperationPending{Token: token}}, nil","handlingStrategy":"validation","validationCode":"tokenLimit := h.config.MaxOperationTokenLength(ns)\nif len(result.Pending.Token) > tokenLimit {\n    return fmt.Errorf(\"token too long: %d/%d\", len(result.Pending.Token), tokenLimit)\n}\nif result.Successful.Size() > h.config.PayloadSizeLimit(ns) {\n    return errors.New(\"response body too large\")\n}","typeGuard":null,"tryCatchPattern":"// Go\nerr := operation.Execute(ctx, req)\nif errors.Is(err, ErrInvalidOperationToken) {\n    // shrink token and retry the handler result, or surface config mismatch\n}","preventionTips":["Keep pending tokens small and opaque; persist large state outside the token","Compute len(token) in handler tests against the lowest configured limit","Sync MaxOperationTokenLength config across environments","Never embed raw payloads or blobs in operation tokens"],"tags":["nexus","nexusoperation","token","validation"],"backgroundTag":"invalid-operation-token","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}