// Copyright 2020-2026 The NATS Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Adapted from server/jetstream_errors.go and server/jetstream_errors_generated.go // in the NATS server Go source. using System.Text.Json.Serialization; namespace ZB.MOM.NatsNet.Server; // --------------------------------------------------------------------------- // JsApiError // --------------------------------------------------------------------------- /// /// Included in all JetStream API responses when there was an error. /// Mirrors ApiError in server/jetstream_errors.go. /// public sealed class JsApiError { [JsonPropertyName("code")] public int Code { get; set; } [JsonPropertyName("err_code")] public ushort ErrCode { get; set; } [JsonPropertyName("description")] public string? Description { get; set; } public override string ToString() => $"{Description} ({ErrCode})"; } // --------------------------------------------------------------------------- // JsApiErrors — all 203 error code constants // --------------------------------------------------------------------------- /// /// Pre-built instances for all JetStream error codes. /// Mirrors the ApiErrors map in server/jetstream_errors_generated.go. /// public static class JsApiErrors { public delegate object? ErrorOption(); // ---- Account ---- public static readonly JsApiError AccountResourcesExceeded = new() { Code = 400, ErrCode = 10002, Description = "resource limits exceeded for account" }; // ---- Atomic Publish ---- public static readonly JsApiError AtomicPublishContainsDuplicateMessage = new() { Code = 400, ErrCode = 10201, Description = "atomic publish batch contains duplicate message id" }; public static readonly JsApiError AtomicPublishDisabled = new() { Code = 400, ErrCode = 10174, Description = "atomic publish is disabled" }; public static readonly JsApiError AtomicPublishIncompleteBatch = new() { Code = 400, ErrCode = 10176, Description = "atomic publish batch is incomplete" }; public static readonly JsApiError AtomicPublishInvalidBatchCommit = new() { Code = 400, ErrCode = 10200, Description = "atomic publish batch commit is invalid" }; public static readonly JsApiError AtomicPublishInvalidBatchID = new() { Code = 400, ErrCode = 10179, Description = "atomic publish batch ID is invalid" }; public static readonly JsApiError AtomicPublishMissingSeq = new() { Code = 400, ErrCode = 10175, Description = "atomic publish sequence is missing" }; public static readonly JsApiError AtomicPublishTooLargeBatch = new() { Code = 400, ErrCode = 10199, Description = "atomic publish batch is too large: {size}" }; public static readonly JsApiError AtomicPublishUnsupportedHeaderBatch = new() { Code = 400, ErrCode = 10177, Description = "atomic publish unsupported header used: {header}" }; // ---- General ---- public static readonly JsApiError BadRequest = new() { Code = 400, ErrCode = 10003, Description = "bad request" }; // ---- Cluster ---- public static readonly JsApiError ClusterIncomplete = new() { Code = 503, ErrCode = 10004, Description = "incomplete results" }; public static readonly JsApiError ClusterNoPeers = new() { Code = 400, ErrCode = 10005, Description = "{err}" }; public static readonly JsApiError ClusterNotActive = new() { Code = 500, ErrCode = 10006, Description = "JetStream not in clustered mode" }; public static readonly JsApiError ClusterNotAssigned = new() { Code = 500, ErrCode = 10007, Description = "JetStream cluster not assigned to this server" }; public static readonly JsApiError ClusterNotAvail = new() { Code = 503, ErrCode = 10008, Description = "JetStream system temporarily unavailable" }; public static readonly JsApiError ClusterNotLeader = new() { Code = 500, ErrCode = 10009, Description = "JetStream cluster can not handle request" }; public static readonly JsApiError ClusterPeerNotMember = new() { Code = 400, ErrCode = 10040, Description = "peer not a member" }; public static readonly JsApiError ClusterRequired = new() { Code = 503, ErrCode = 10010, Description = "JetStream clustering support required" }; public static readonly JsApiError ClusterServerMemberChangeInflight = new() { Code = 400, ErrCode = 10202, Description = "cluster member change is in progress" }; public static readonly JsApiError ClusterServerNotMember = new() { Code = 400, ErrCode = 10044, Description = "server is not a member of the cluster" }; public static readonly JsApiError ClusterTags = new() { Code = 400, ErrCode = 10011, Description = "tags placement not supported for operation" }; public static readonly JsApiError ClusterUnSupportFeature = new() { Code = 503, ErrCode = 10036, Description = "not currently supported in clustered mode" }; // ---- Consumer ---- public static readonly JsApiError ConsumerAckPolicyInvalid = new() { Code = 400, ErrCode = 10181, Description = "consumer ack policy invalid" }; public static readonly JsApiError ConsumerAckWaitNegative = new() { Code = 400, ErrCode = 10183, Description = "consumer ack wait needs to be positive" }; public static readonly JsApiError ConsumerAlreadyExists = new() { Code = 400, ErrCode = 10148, Description = "consumer already exists" }; public static readonly JsApiError ConsumerBackOffNegative = new() { Code = 400, ErrCode = 10184, Description = "consumer backoff needs to be positive" }; public static readonly JsApiError ConsumerBadDurableName = new() { Code = 400, ErrCode = 10103, Description = "durable name can not contain '.', '*', '>'" }; public static readonly JsApiError ConsumerConfigRequired = new() { Code = 400, ErrCode = 10078, Description = "consumer config required" }; public static readonly JsApiError ConsumerCreateDurableAndNameMismatch = new() { Code = 400, ErrCode = 10132, Description = "Consumer Durable and Name have to be equal if both are provided" }; public static readonly JsApiError ConsumerCreateErr = new() { Code = 500, ErrCode = 10012, Description = "{err}" }; public static readonly JsApiError ConsumerCreateFilterSubjectMismatch = new() { Code = 400, ErrCode = 10131, Description = "Consumer create request did not match filtered subject from create subject" }; public static readonly JsApiError ConsumerDeliverCycle = new() { Code = 400, ErrCode = 10081, Description = "consumer deliver subject forms a cycle" }; public static readonly JsApiError ConsumerDeliverToWildcards = new() { Code = 400, ErrCode = 10079, Description = "consumer deliver subject has wildcards" }; public static readonly JsApiError ConsumerDescriptionTooLong = new() { Code = 400, ErrCode = 10107, Description = "consumer description is too long, maximum allowed is {max}" }; public static readonly JsApiError ConsumerDirectRequiresEphemeral = new() { Code = 400, ErrCode = 10091, Description = "consumer direct requires an ephemeral consumer" }; public static readonly JsApiError ConsumerDirectRequiresPush = new() { Code = 400, ErrCode = 10090, Description = "consumer direct requires a push based consumer" }; public static readonly JsApiError ConsumerDoesNotExist = new() { Code = 400, ErrCode = 10149, Description = "consumer does not exist" }; public static readonly JsApiError ConsumerDuplicateFilterSubjects = new() { Code = 400, ErrCode = 10136, Description = "consumer cannot have both FilterSubject and FilterSubjects specified" }; public static readonly JsApiError ConsumerDurableNameNotInSubject = new() { Code = 400, ErrCode = 10016, Description = "consumer expected to be durable but no durable name set in subject" }; public static readonly JsApiError ConsumerDurableNameNotMatchSubject = new() { Code = 400, ErrCode = 10017, Description = "consumer name in subject does not match durable name in request" }; public static readonly JsApiError ConsumerDurableNameNotSet = new() { Code = 400, ErrCode = 10018, Description = "consumer expected to be durable but a durable name was not set" }; public static readonly JsApiError ConsumerEmptyFilter = new() { Code = 400, ErrCode = 10139, Description = "consumer filter in FilterSubjects cannot be empty" }; public static readonly JsApiError ConsumerEmptyGroupName = new() { Code = 400, ErrCode = 10161, Description = "Group name cannot be an empty string" }; public static readonly JsApiError ConsumerEphemeralWithDurableInSubject = new() { Code = 400, ErrCode = 10019, Description = "consumer expected to be ephemeral but detected a durable name set in subject" }; public static readonly JsApiError ConsumerEphemeralWithDurableName = new() { Code = 400, ErrCode = 10020, Description = "consumer expected to be ephemeral but a durable name was set in request" }; public static readonly JsApiError ConsumerExistingActive = new() { Code = 400, ErrCode = 10105, Description = "consumer already exists and is still active" }; public static readonly JsApiError ConsumerFCRequiresPush = new() { Code = 400, ErrCode = 10089, Description = "consumer flow control requires a push based consumer" }; public static readonly JsApiError ConsumerFilterNotSubset = new() { Code = 400, ErrCode = 10093, Description = "consumer filter subject is not a valid subset of the interest subjects" }; public static readonly JsApiError ConsumerHBRequiresPush = new() { Code = 400, ErrCode = 10088, Description = "consumer idle heartbeat requires a push based consumer" }; public static readonly JsApiError ConsumerInactiveThresholdExcess = new() { Code = 400, ErrCode = 10153, Description = "consumer inactive threshold exceeds system limit of {limit}" }; public static readonly JsApiError ConsumerInvalidDeliverSubject = new() { Code = 400, ErrCode = 10112, Description = "invalid push consumer deliver subject" }; public static readonly JsApiError ConsumerInvalidGroupName = new() { Code = 400, ErrCode = 10162, Description = "Valid priority group name must match A-Z, a-z, 0-9, -_/=)+ and may not exceed 16 characters" }; public static readonly JsApiError ConsumerInvalidPolicy = new() { Code = 400, ErrCode = 10094, Description = "{err}" }; public static readonly JsApiError ConsumerInvalidPriorityGroup = new() { Code = 400, ErrCode = 10160, Description = "Provided priority group does not exist for this consumer" }; public static readonly JsApiError ConsumerInvalidReset = new() { Code = 400, ErrCode = 10204, Description = "invalid reset: {err}" }; public static readonly JsApiError ConsumerInvalidSampling = new() { Code = 400, ErrCode = 10095, Description = "failed to parse consumer sampling configuration: {err}" }; public static readonly JsApiError ConsumerMaxDeliverBackoff = new() { Code = 400, ErrCode = 10116, Description = "max deliver is required to be > length of backoff values" }; public static readonly JsApiError ConsumerMaxPendingAckExcess = new() { Code = 400, ErrCode = 10121, Description = "consumer max ack pending exceeds system limit of {limit}" }; public static readonly JsApiError ConsumerMaxPendingAckPolicyRequired = new() { Code = 400, ErrCode = 10082, Description = "consumer requires ack policy for max ack pending" }; public static readonly JsApiError ConsumerMaxRequestBatchExceeded = new() { Code = 400, ErrCode = 10125, Description = "consumer max request batch exceeds server limit of {limit}" }; public static readonly JsApiError ConsumerMaxRequestBatchNegative = new() { Code = 400, ErrCode = 10114, Description = "consumer max request batch needs to be > 0" }; public static readonly JsApiError ConsumerMaxRequestExpiresTooSmall = new() { Code = 400, ErrCode = 10115, Description = "consumer max request expires needs to be >= 1ms" }; public static readonly JsApiError ConsumerMaxWaitingNegative = new() { Code = 400, ErrCode = 10087, Description = "consumer max waiting needs to be positive" }; public static readonly JsApiError ConsumerMetadataLength = new() { Code = 400, ErrCode = 10135, Description = "consumer metadata exceeds maximum size of {limit}" }; public static readonly JsApiError ConsumerMultipleFiltersNotAllowed = new() { Code = 400, ErrCode = 10137, Description = "consumer with multiple subject filters cannot use subject based API" }; public static readonly JsApiError ConsumerNameContainsPathSeparators = new() { Code = 400, ErrCode = 10127, Description = "Consumer name can not contain path separators" }; public static readonly JsApiError ConsumerNameExist = new() { Code = 400, ErrCode = 10013, Description = "consumer name already in use" }; public static readonly JsApiError ConsumerNameTooLong = new() { Code = 400, ErrCode = 10102, Description = "consumer name is too long, maximum allowed is {max}" }; public static readonly JsApiError ConsumerNotFound = new() { Code = 404, ErrCode = 10014, Description = "consumer not found" }; public static readonly JsApiError ConsumerOffline = new() { Code = 500, ErrCode = 10119, Description = "consumer is offline" }; public static readonly JsApiError ConsumerOfflineReason = new() { Code = 500, ErrCode = 10195, Description = "consumer is offline: {err}" }; public static readonly JsApiError ConsumerOnMapped = new() { Code = 400, ErrCode = 10092, Description = "consumer direct on a mapped consumer" }; public static readonly JsApiError ConsumerOverlappingSubjectFilters = new() { Code = 400, ErrCode = 10138, Description = "consumer subject filters cannot overlap" }; public static readonly JsApiError ConsumerPinnedTTLWithoutPriorityPolicyNone = new() { Code = 400, ErrCode = 10197, Description = "PinnedTTL cannot be set when PriorityPolicy is none" }; public static readonly JsApiError ConsumerPriorityGroupWithPolicyNone = new() { Code = 400, ErrCode = 10196, Description = "consumer can not have priority groups when policy is none" }; public static readonly JsApiError ConsumerPriorityPolicyWithoutGroup = new() { Code = 400, ErrCode = 10159, Description = "Setting PriorityPolicy requires at least one PriorityGroup to be set" }; public static readonly JsApiError ConsumerPullNotDurable = new() { Code = 400, ErrCode = 10085, Description = "consumer in pull mode requires a durable name" }; public static readonly JsApiError ConsumerPullRequiresAck = new() { Code = 400, ErrCode = 10084, Description = "consumer in pull mode requires explicit ack policy on workqueue stream" }; public static readonly JsApiError ConsumerPullWithRateLimit = new() { Code = 400, ErrCode = 10086, Description = "consumer in pull mode can not have rate limit set" }; public static readonly JsApiError ConsumerPushMaxWaiting = new() { Code = 400, ErrCode = 10080, Description = "consumer in push mode can not set max waiting" }; public static readonly JsApiError ConsumerPushWithPriorityGroup = new() { Code = 400, ErrCode = 10178, Description = "priority groups can not be used with push consumers" }; public static readonly JsApiError ConsumerReplacementWithDifferentName = new() { Code = 400, ErrCode = 10106, Description = "consumer replacement durable config not the same" }; public static readonly JsApiError ConsumerReplayPolicyInvalid = new() { Code = 400, ErrCode = 10182, Description = "consumer replay policy invalid" }; public static readonly JsApiError ConsumerReplicasExceedsStream = new() { Code = 400, ErrCode = 10126, Description = "consumer config replica count exceeds parent stream" }; public static readonly JsApiError ConsumerReplicasShouldMatchStream = new() { Code = 400, ErrCode = 10134, Description = "consumer config replicas must match interest retention stream's replicas" }; public static readonly JsApiError ConsumerSmallHeartbeat = new() { Code = 400, ErrCode = 10083, Description = "consumer idle heartbeat needs to be >= 100ms" }; public static readonly JsApiError ConsumerStoreFailed = new() { Code = 500, ErrCode = 10104, Description = "error creating store for consumer: {err}" }; public static readonly JsApiError ConsumerWQConsumerNotDeliverAll = new() { Code = 400, ErrCode = 10101, Description = "consumer must be deliver all on workqueue stream" }; public static readonly JsApiError ConsumerWQConsumerNotUnique = new() { Code = 400, ErrCode = 10100, Description = "filtered consumer not unique on workqueue stream" }; public static readonly JsApiError ConsumerWQMultipleUnfiltered = new() { Code = 400, ErrCode = 10099, Description = "multiple non-filtered consumers not allowed on workqueue stream" }; public static readonly JsApiError ConsumerWQRequiresExplicitAck = new() { Code = 400, ErrCode = 10098, Description = "workqueue stream requires explicit ack" }; public static readonly JsApiError ConsumerWithFlowControlNeedsHeartbeats = new() { Code = 400, ErrCode = 10108, Description = "consumer with flow control also needs heartbeats" }; // ---- Resources ---- public static readonly JsApiError InsufficientResources = new() { Code = 503, ErrCode = 10023, Description = "insufficient resources" }; public static readonly JsApiError InvalidJSON = new() { Code = 400, ErrCode = 10025, Description = "invalid JSON: {err}" }; public static readonly JsApiError MaximumConsumersLimit = new() { Code = 400, ErrCode = 10026, Description = "maximum consumers limit reached" }; public static readonly JsApiError MaximumStreamsLimit = new() { Code = 400, ErrCode = 10027, Description = "maximum number of streams reached" }; public static readonly JsApiError MemoryResourcesExceeded = new() { Code = 500, ErrCode = 10028, Description = "insufficient memory resources available" }; // ---- Message Counter ---- public static readonly JsApiError MessageCounterBroken = new() { Code = 400, ErrCode = 10172, Description = "message counter is broken" }; public static readonly JsApiError MessageIncrDisabled = new() { Code = 400, ErrCode = 10168, Description = "message counters is disabled" }; public static readonly JsApiError MessageIncrInvalid = new() { Code = 400, ErrCode = 10171, Description = "message counter increment is invalid" }; public static readonly JsApiError MessageIncrMissing = new() { Code = 400, ErrCode = 10169, Description = "message counter increment is missing" }; public static readonly JsApiError MessageIncrPayload = new() { Code = 400, ErrCode = 10170, Description = "message counter has payload" }; // ---- Message Schedules ---- public static readonly JsApiError MessageSchedulesDisabled = new() { Code = 400, ErrCode = 10188, Description = "message schedules is disabled" }; public static readonly JsApiError MessageSchedulesPatternInvalid = new() { Code = 400, ErrCode = 10189, Description = "message schedules pattern is invalid" }; public static readonly JsApiError MessageSchedulesRollupInvalid = new() { Code = 400, ErrCode = 10192, Description = "message schedules invalid rollup" }; public static readonly JsApiError MessageSchedulesSourceInvalid = new() { Code = 400, ErrCode = 10203, Description = "message schedules source is invalid" }; public static readonly JsApiError MessageSchedulesTTLInvalid = new() { Code = 400, ErrCode = 10191, Description = "message schedules invalid per-message TTL" }; public static readonly JsApiError MessageSchedulesTargetInvalid = new() { Code = 400, ErrCode = 10190, Description = "message schedules target is invalid" }; // ---- Message TTL ---- public static readonly JsApiError MessageTTLDisabled = new() { Code = 400, ErrCode = 10166, Description = "per-message TTL is disabled" }; public static readonly JsApiError MessageTTLInvalid = new() { Code = 400, ErrCode = 10165, Description = "invalid per-message TTL" }; // ---- Mirror ---- public static readonly JsApiError MirrorConsumerSetupFailed = new() { Code = 500, ErrCode = 10029, Description = "{err}" }; public static readonly JsApiError MirrorInvalidStreamName = new() { Code = 400, ErrCode = 10142, Description = "mirrored stream name is invalid" }; public static readonly JsApiError MirrorInvalidSubjectFilter = new() { Code = 400, ErrCode = 10151, Description = "mirror transform source: {err}" }; public static readonly JsApiError MirrorInvalidTransformDestination = new() { Code = 400, ErrCode = 10154, Description = "mirror transform: {err}" }; public static readonly JsApiError MirrorMaxMessageSizeTooBig = new() { Code = 400, ErrCode = 10030, Description = "stream mirror must have max message size >= source" }; public static readonly JsApiError MirrorMultipleFiltersNotAllowed = new() { Code = 400, ErrCode = 10150, Description = "mirror with multiple subject transforms cannot also have a single subject filter" }; public static readonly JsApiError MirrorOverlappingSubjectFilters = new() { Code = 400, ErrCode = 10152, Description = "mirror subject filters can not overlap" }; public static readonly JsApiError MirrorWithAtomicPublish = new() { Code = 400, ErrCode = 10198, Description = "stream mirrors can not also use atomic publishing" }; public static readonly JsApiError MirrorWithCounters = new() { Code = 400, ErrCode = 10173, Description = "stream mirrors can not also calculate counters" }; public static readonly JsApiError MirrorWithFirstSeq = new() { Code = 400, ErrCode = 10143, Description = "stream mirrors can not have first sequence configured" }; public static readonly JsApiError MirrorWithMsgSchedules = new() { Code = 400, ErrCode = 10186, Description = "stream mirrors can not also schedule messages" }; public static readonly JsApiError MirrorWithSources = new() { Code = 400, ErrCode = 10031, Description = "stream mirrors can not also contain other sources" }; public static readonly JsApiError MirrorWithStartSeqAndTime = new() { Code = 400, ErrCode = 10032, Description = "stream mirrors can not have both start seq and start time configured" }; public static readonly JsApiError MirrorWithSubjectFilters = new() { Code = 400, ErrCode = 10033, Description = "stream mirrors can not contain filtered subjects" }; public static readonly JsApiError MirrorWithSubjects = new() { Code = 400, ErrCode = 10034, Description = "stream mirrors can not contain subjects" }; // ---- Misc ---- public static readonly JsApiError NoAccount = new() { Code = 503, ErrCode = 10035, Description = "account not found" }; public static readonly JsApiError NoLimits = new() { Code = 400, ErrCode = 10120, Description = "no JetStream default or applicable tiered limit present" }; public static readonly JsApiError NoMessageFound = new() { Code = 404, ErrCode = 10037, Description = "no message found" }; public static readonly JsApiError NotEmptyRequest = new() { Code = 400, ErrCode = 10038, Description = "expected an empty request payload" }; public static readonly JsApiError NotEnabled = new() { Code = 503, ErrCode = 10076, Description = "JetStream not enabled" }; public static readonly JsApiError NotEnabledForAccount = new() { Code = 503, ErrCode = 10039, Description = "JetStream not enabled for account" }; public static readonly JsApiError Pedantic = new() { Code = 400, ErrCode = 10157, Description = "pedantic mode: {err}" }; public static readonly JsApiError PeerRemap = new() { Code = 503, ErrCode = 10075, Description = "peer remap failed" }; // ---- RAFT ---- public static readonly JsApiError RaftGeneralErr = new() { Code = 500, ErrCode = 10041, Description = "{err}" }; // ---- Replicas ---- public static readonly JsApiError ReplicasCountCannotBeNegative = new() { Code = 400, ErrCode = 10133, Description = "replicas count cannot be negative" }; public static readonly JsApiError RequiredApiLevel = new() { Code = 412, ErrCode = 10185, Description = "JetStream minimum api level required" }; // ---- Restore ---- public static readonly JsApiError RestoreSubscribeFailed = new() { Code = 500, ErrCode = 10042, Description = "JetStream unable to subscribe to restore snapshot {subject}: {err}" }; // ---- Sequence ---- public static readonly JsApiError SequenceNotFound = new() { Code = 400, ErrCode = 10043, Description = "sequence {seq} not found" }; public static readonly JsApiError SnapshotDeliverSubjectInvalid = new() { Code = 400, ErrCode = 10015, Description = "deliver subject not valid" }; // ---- Source ---- public static readonly JsApiError SourceConsumerSetupFailed = new() { Code = 500, ErrCode = 10045, Description = "{err}" }; public static readonly JsApiError SourceDuplicateDetected = new() { Code = 400, ErrCode = 10140, Description = "duplicate source configuration detected" }; public static readonly JsApiError SourceInvalidStreamName = new() { Code = 400, ErrCode = 10141, Description = "sourced stream name is invalid" }; public static readonly JsApiError SourceInvalidSubjectFilter = new() { Code = 400, ErrCode = 10145, Description = "source transform source: {err}" }; public static readonly JsApiError SourceInvalidTransformDestination = new() { Code = 400, ErrCode = 10146, Description = "source transform: {err}" }; public static readonly JsApiError SourceMaxMessageSizeTooBig = new() { Code = 400, ErrCode = 10046, Description = "stream source must have max message size >= target" }; public static readonly JsApiError SourceMultipleFiltersNotAllowed = new() { Code = 400, ErrCode = 10144, Description = "source with multiple subject transforms cannot also have a single subject filter" }; public static readonly JsApiError SourceOverlappingSubjectFilters = new() { Code = 400, ErrCode = 10147, Description = "source filters can not overlap" }; public static readonly JsApiError SourceWithMsgSchedules = new() { Code = 400, ErrCode = 10187, Description = "stream source can not also schedule messages" }; // ---- Storage ---- public static readonly JsApiError StorageResourcesExceeded = new() { Code = 500, ErrCode = 10047, Description = "insufficient storage resources available" }; // ---- Stream ---- public static readonly JsApiError StreamAssignment = new() { Code = 500, ErrCode = 10048, Description = "{err}" }; public static readonly JsApiError StreamCreate = new() { Code = 500, ErrCode = 10049, Description = "{err}" }; public static readonly JsApiError StreamDelete = new() { Code = 500, ErrCode = 10050, Description = "{err}" }; public static readonly JsApiError StreamDuplicateMessageConflict = new() { Code = 409, ErrCode = 10158, Description = "duplicate message id is in process" }; public static readonly JsApiError StreamExpectedLastSeqPerSubjectInvalid = new() { Code = 400, ErrCode = 10193, Description = "missing sequence for expected last sequence per subject" }; public static readonly JsApiError StreamExpectedLastSeqPerSubjectNotReady = new() { Code = 503, ErrCode = 10163, Description = "expected last sequence per subject temporarily unavailable" }; public static readonly JsApiError StreamExternalApiOverlap = new() { Code = 400, ErrCode = 10021, Description = "stream external api prefix {prefix} must not overlap with {subject}" }; public static readonly JsApiError StreamExternalDelPrefixOverlaps = new() { Code = 400, ErrCode = 10022, Description = "stream external delivery prefix {prefix} overlaps with stream subject {subject}" }; public static readonly JsApiError StreamGeneralError = new() { Code = 500, ErrCode = 10051, Description = "{err}" }; public static readonly JsApiError StreamHeaderExceedsMaximum = new() { Code = 400, ErrCode = 10097, Description = "header size exceeds maximum allowed of 64k" }; public static readonly JsApiError StreamInfoMaxSubjects = new() { Code = 500, ErrCode = 10117, Description = "subject details would exceed maximum allowed" }; public static readonly JsApiError StreamInvalidConfig = new() { Code = 500, ErrCode = 10052, Description = "{err}" }; public static readonly JsApiError StreamInvalid = new() { Code = 500, ErrCode = 10096, Description = "stream not valid" }; public static readonly JsApiError StreamInvalidExternalDeliverySubj = new() { Code = 400, ErrCode = 10024, Description = "stream external delivery prefix {prefix} must not contain wildcards" }; public static readonly JsApiError StreamLimits = new() { Code = 500, ErrCode = 10053, Description = "{err}" }; public static readonly JsApiError StreamMaxBytesRequired = new() { Code = 400, ErrCode = 10113, Description = "account requires a stream config to have max bytes set" }; public static readonly JsApiError StreamMaxStreamBytesExceeded = new() { Code = 400, ErrCode = 10122, Description = "stream max bytes exceeds account limit max stream bytes" }; public static readonly JsApiError StreamMessageExceedsMaximum = new() { Code = 400, ErrCode = 10054, Description = "message size exceeds maximum allowed" }; public static readonly JsApiError StreamMinLastSeq = new() { Code = 412, ErrCode = 10180, Description = "min last sequence" }; public static readonly JsApiError StreamMirrorNotUpdatable = new() { Code = 400, ErrCode = 10055, Description = "stream mirror configuration can not be updated" }; public static readonly JsApiError StreamMismatch = new() { Code = 400, ErrCode = 10056, Description = "stream name in subject does not match request" }; public static readonly JsApiError StreamMoveAndScale = new() { Code = 400, ErrCode = 10123, Description = "can not move and scale a stream in a single update" }; public static readonly JsApiError StreamMoveInProgress = new() { Code = 400, ErrCode = 10124, Description = "stream move already in progress: {msg}" }; public static readonly JsApiError StreamMoveNotInProgress = new() { Code = 400, ErrCode = 10129, Description = "stream move not in progress" }; public static readonly JsApiError StreamMsgDeleteFailed = new() { Code = 500, ErrCode = 10057, Description = "{err}" }; public static readonly JsApiError StreamNameContainsPathSeparators = new() { Code = 400, ErrCode = 10128, Description = "Stream name can not contain path separators" }; public static readonly JsApiError StreamNameExist = new() { Code = 400, ErrCode = 10058, Description = "stream name already in use with a different configuration" }; public static readonly JsApiError StreamNameExistRestoreFailed = new() { Code = 400, ErrCode = 10130, Description = "stream name already in use, cannot restore" }; public static readonly JsApiError StreamNotFound = new() { Code = 404, ErrCode = 10059, Description = "stream not found" }; public static readonly JsApiError StreamNotMatch = new() { Code = 400, ErrCode = 10060, Description = "expected stream does not match" }; public static readonly JsApiError StreamOffline = new() { Code = 500, ErrCode = 10118, Description = "stream is offline" }; public static readonly JsApiError StreamOfflineReason = new() { Code = 500, ErrCode = 10194, Description = "stream is offline: {err}" }; public static readonly JsApiError StreamPurgeFailed = new() { Code = 500, ErrCode = 10110, Description = "{err}" }; public static readonly JsApiError StreamReplicasNotSupported = new() { Code = 500, ErrCode = 10074, Description = "replicas > 1 not supported in non-clustered mode" }; public static readonly JsApiError StreamReplicasNotUpdatable = new() { Code = 400, ErrCode = 10061, Description = "Replicas configuration can not be updated" }; public static readonly JsApiError StreamRestore = new() { Code = 500, ErrCode = 10062, Description = "restore failed: {err}" }; public static readonly JsApiError StreamRollupFailed = new() { Code = 500, ErrCode = 10111, Description = "{err}" }; public static readonly JsApiError StreamSealed = new() { Code = 400, ErrCode = 10109, Description = "invalid operation on sealed stream" }; public static readonly JsApiError StreamSequenceNotMatch = new() { Code = 503, ErrCode = 10063, Description = "expected stream sequence does not match" }; public static readonly JsApiError StreamSnapshot = new() { Code = 500, ErrCode = 10064, Description = "snapshot failed: {err}" }; public static readonly JsApiError StreamStoreFailed = new() { Code = 503, ErrCode = 10077, Description = "{err}" }; public static readonly JsApiError StreamSubjectOverlap = new() { Code = 400, ErrCode = 10065, Description = "subjects overlap with an existing stream" }; public static readonly JsApiError StreamTemplateCreate = new() { Code = 500, ErrCode = 10066, Description = "{err}" }; public static readonly JsApiError StreamTemplateDelete = new() { Code = 500, ErrCode = 10067, Description = "{err}" }; public static readonly JsApiError StreamTemplateNotFound = new() { Code = 404, ErrCode = 10068, Description = "template not found" }; public static readonly JsApiError StreamTooManyRequests = new() { Code = 429, ErrCode = 10167, Description = "too many requests" }; public static readonly JsApiError StreamTransformInvalidDestination = new() { Code = 400, ErrCode = 10156, Description = "stream transform: {err}" }; public static readonly JsApiError StreamTransformInvalidSource = new() { Code = 400, ErrCode = 10155, Description = "stream transform source: {err}" }; public static readonly JsApiError StreamUpdate = new() { Code = 500, ErrCode = 10069, Description = "{err}" }; public static readonly JsApiError StreamWrongLastMsgID = new() { Code = 400, ErrCode = 10070, Description = "wrong last msg ID: {id}" }; public static readonly JsApiError StreamWrongLastSequenceConstant = new() { Code = 400, ErrCode = 10164, Description = "wrong last sequence" }; public static readonly JsApiError StreamWrongLastSequence = new() { Code = 400, ErrCode = 10071, Description = "wrong last sequence: {seq}" }; // ---- Temp storage ---- public static readonly JsApiError TempStorageFailed = new() { Code = 500, ErrCode = 10072, Description = "JetStream unable to open temp storage for restore" }; public static readonly JsApiError TemplateNameNotMatchSubject = new() { Code = 400, ErrCode = 10073, Description = "template name in subject does not match request" }; // --------------------------------------------------------------------------- // Lookup by ErrCode // --------------------------------------------------------------------------- private static readonly Dictionary _byErrCode; static JsApiErrors() { _byErrCode = new Dictionary(); foreach (var field in typeof(JsApiErrors).GetFields( System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static)) { if (field.GetValue(null) is JsApiError e) _byErrCode.TryAdd(e.ErrCode, e); } } /// /// Returns the pre-built for the given err_code, or null if not found. /// public static JsApiError? ForErrCode(ushort errCode) => _byErrCode.TryGetValue(errCode, out var e) ? e : null; /// /// Returns true if the given matches one or more of the supplied err_codes. /// Mirrors IsNatsErr in server/jetstream_errors.go. /// public static bool IsNatsError(JsApiError? err, params ushort[] errCodes) { return IsNatsErr(err, errCodes); } /// /// Returns true if is a and matches one of the supplied IDs. /// Unknown IDs are ignored, matching Go's map-based lookup behavior. /// public static bool IsNatsErr(object? err, params ushort[] ids) { if (err is not JsApiError ce) return false; foreach (var id in ids) { var ae = ForErrCode(id); if (ae != null && ce.ErrCode == ae.ErrCode) return true; } return false; } /// /// Formats an API error string exactly as Go ApiError.Error(). /// public static string Error(JsApiError? err) => err?.ToString() ?? string.Empty; /// /// Creates an option that causes constructor helpers to return the provided /// when present. /// Mirrors Go Unless. /// public static ErrorOption Unless(object? err) => () => err; /// /// Mirrors Go NewJSRestoreSubscribeFailedError. /// public static JsApiError NewJSRestoreSubscribeFailedError(Exception err, string subject, params ErrorOption[] opts) { var overridden = ParseUnless(opts); if (overridden != null) return overridden; return NewWithTags( RestoreSubscribeFailed, ("{err}", err.Message), ("{subject}", subject)); } /// /// Mirrors Go NewJSStreamRestoreError. /// public static JsApiError NewJSStreamRestoreError(Exception err, params ErrorOption[] opts) { var overridden = ParseUnless(opts); if (overridden != null) return overridden; return NewWithTags(StreamRestore, ("{err}", err.Message)); } /// /// Mirrors Go NewJSPeerRemapError. /// public static JsApiError NewJSPeerRemapError(params ErrorOption[] opts) { var overridden = ParseUnless(opts); return overridden ?? Clone(PeerRemap); } private static JsApiError? ParseUnless(ReadOnlySpan opts) { foreach (var opt in opts) { var value = opt(); if (value is JsApiError apiErr) return Clone(apiErr); } return null; } private static JsApiError Clone(JsApiError source) => new() { Code = source.Code, ErrCode = source.ErrCode, Description = source.Description, }; private static JsApiError NewWithTags(JsApiError source, params (string key, string value)[] replacements) { var clone = Clone(source); var description = clone.Description ?? string.Empty; foreach (var (key, value) in replacements) description = description.Replace(key, value, StringComparison.Ordinal); clone.Description = description; return clone; } }