Files
qfixpt/quickfix/errors.go
2026-03-12 12:08:34 -03:00

191 lines
8.7 KiB
Go

// Copyright (c) quickfixengine.org All rights reserved.
//
// This file may be distributed under the terms of the quickfixengine.org
// license as defined by quickfixengine.org and appearing in the file
// LICENSE included in the packaging of this file.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE.
//
// See http://www.quickfixengine.org/LICENSE for licensing information.
//
// Contact ask@quickfixengine.org if any conditions of this licensing
// are not clear to you.
package quickfix
import (
"errors"
"fmt"
)
// ErrDoNotSend is a convenience error to indicate a DoNotSend in ToApp.
var ErrDoNotSend = errors.New("Do Not Send")
// rejectReason enum values.
const (
rejectReasonInvalidTagNumber = 0
rejectReasonRequiredTagMissing = 1
rejectReasonTagNotDefinedForThisMessageType = 2
rejectReasonUnsupportedMessageType = 3
rejectReasonTagSpecifiedWithoutAValue = 4
rejectReasonValueIsIncorrect = 5
rejectReasonConditionallyRequiredFieldMissing = 5
rejectReasonIncorrectDataFormatForValue = 6
rejectReasonCompIDProblem = 9
rejectReasonSendingTimeAccuracyProblem = 10
rejectReasonInvalidMsgType = 11
rejectReasonTagAppearsMoreThanOnce = 13
rejectReasonTagSpecifiedOutOfRequiredOrder = 14
rejectReasonRepeatingGroupFieldsOutOfOrder = 15
rejectReasonIncorrectNumInGroupCountForRepeatingGroup = 16
)
// MessageRejectError is a type of error that can correlate to a message reject.
type MessageRejectError interface {
error
// RejectReason, tag 373 for session rejects, tag 380 for business rejects.
RejectReason() int
BusinessRejectRefID() string
RefTagID() *Tag
IsBusinessReject() bool
}
// RejectLogon indicates the application is rejecting permission to logon. Implements MessageRejectError.
type RejectLogon struct {
Text string
}
func (e RejectLogon) Error() string { return e.Text }
// RefTagID implements MessageRejectError.
func (RejectLogon) RefTagID() *Tag { return nil }
// RejectReason implements MessageRejectError.
func (RejectLogon) RejectReason() int { return 0 }
// BusinessRejectRefID implements MessageRejectError.
func (RejectLogon) BusinessRejectRefID() string { return "" }
// IsBusinessReject implements MessageRejectError.
func (RejectLogon) IsBusinessReject() bool { return false }
type messageRejectError struct {
rejectReason int
text string
businessRejectRefID string
refTagID *Tag
isBusinessReject bool
}
func (e messageRejectError) Error() string { return e.text }
func (e messageRejectError) RefTagID() *Tag { return e.refTagID }
func (e messageRejectError) RejectReason() int { return e.rejectReason }
func (e messageRejectError) BusinessRejectRefID() string { return e.businessRejectRefID }
func (e messageRejectError) IsBusinessReject() bool { return e.isBusinessReject }
// NewMessageRejectError returns a MessageRejectError with the given error message, reject reason, and optional reftagid.
func NewMessageRejectError(err string, rejectReason int, refTagID *Tag) MessageRejectError {
return messageRejectError{text: err, rejectReason: rejectReason, refTagID: refTagID}
}
// NewBusinessMessageRejectError returns a MessageRejectError with the given error mesage, reject reason, and optional reftagid.
// Reject is treated as a business level reject.
func NewBusinessMessageRejectError(err string, rejectReason int, refTagID *Tag) MessageRejectError {
return messageRejectError{text: err, rejectReason: rejectReason, refTagID: refTagID, isBusinessReject: true}
}
// NewBusinessMessageRejectErrorWithRefID returns a MessageRejectError with the given error mesage, reject reason, refID, and optional reftagid.
// Reject is treated as a business level reject.
func NewBusinessMessageRejectErrorWithRefID(err string, rejectReason int, businessRejectRefID string, refTagID *Tag) MessageRejectError {
return messageRejectError{text: err, rejectReason: rejectReason, refTagID: refTagID, businessRejectRefID: businessRejectRefID, isBusinessReject: true}
}
// IncorrectDataFormatForValue returns an error indicating a field that cannot be parsed as the type required.
func IncorrectDataFormatForValue(tag Tag) MessageRejectError {
return NewMessageRejectError("Incorrect data format for value", rejectReasonIncorrectDataFormatForValue, &tag)
}
// repeatingGroupFieldsOutOfOrder returns an error indicating a problem parsing repeating groups fields.
func repeatingGroupFieldsOutOfOrder(tag Tag, reason string) MessageRejectError {
if reason != "" {
reason = fmt.Sprintf("Repeating group fields out of order (%s)", reason)
} else {
reason = "Repeating group fields out of order"
}
return NewMessageRejectError(reason, rejectReasonRepeatingGroupFieldsOutOfOrder, &tag)
}
// ValueIsIncorrect returns an error indicating a field with value that is not valid.
func ValueIsIncorrect(tag Tag) MessageRejectError {
return NewMessageRejectError("Value is incorrect (out of range) for this tag", rejectReasonValueIsIncorrect, &tag)
}
// ConditionallyRequiredFieldMissing indicates that the requested field could not be found in the FIX message.
func ConditionallyRequiredFieldMissing(tag Tag) MessageRejectError {
return NewBusinessMessageRejectError(fmt.Sprintf("Conditionally Required Field Missing (%d)", tag), rejectReasonConditionallyRequiredFieldMissing, &tag)
}
// valueIsIncorrectNoTag returns an error indicating a field with value that is not valid.
// FIXME: to be compliant with legacy tests, for certain value issues, do not include reftag? (11c_NewSeqNoLess).
func valueIsIncorrectNoTag() MessageRejectError {
return NewMessageRejectError("Value is incorrect (out of range) for this tag", rejectReasonValueIsIncorrect, nil)
}
// InvalidMessageType returns an error to indicate an invalid message type.
func InvalidMessageType() MessageRejectError {
return NewMessageRejectError("Invalid MsgType", rejectReasonInvalidMsgType, nil)
}
// UnsupportedMessageType returns an error to indicate an unhandled message.
func UnsupportedMessageType() MessageRejectError {
return NewBusinessMessageRejectError("Unsupported Message Type", rejectReasonUnsupportedMessageType, nil)
}
// TagNotDefinedForThisMessageType returns an error for an invalid tag appearing in a message.
func TagNotDefinedForThisMessageType(tag Tag) MessageRejectError {
return NewMessageRejectError("Tag not defined for this message type", rejectReasonTagNotDefinedForThisMessageType, &tag)
}
// tagAppearsMoreThanOnce return an error for multiple tags in a message not detected as a repeating group.
func tagAppearsMoreThanOnce(tag Tag) MessageRejectError {
return NewMessageRejectError("Tag appears more than once", rejectReasonTagAppearsMoreThanOnce, &tag)
}
// RequiredTagMissing returns a validation error when a required field cannot be found in a message.
func RequiredTagMissing(tag Tag) MessageRejectError {
return NewMessageRejectError("Required tag missing", rejectReasonRequiredTagMissing, &tag)
}
// incorrectNumInGroupCountForRepeatingGroup returns a validation error when the num in group value for a group does not match actual group size.
func incorrectNumInGroupCountForRepeatingGroup(tag Tag) MessageRejectError {
return NewMessageRejectError("Incorrect NumInGroup count for repeating group", rejectReasonIncorrectNumInGroupCountForRepeatingGroup, &tag)
}
// tagSpecifiedOutOfRequiredOrder returns validation error when the group order does not match the spec.
func tagSpecifiedOutOfRequiredOrder(tag Tag) MessageRejectError {
return NewMessageRejectError("Tag specified out of required order", rejectReasonTagSpecifiedOutOfRequiredOrder, &tag)
}
// TagSpecifiedWithoutAValue returns a validation error for when a field has no value.
func TagSpecifiedWithoutAValue(tag Tag) MessageRejectError {
return NewMessageRejectError("Tag specified without a value", rejectReasonTagSpecifiedWithoutAValue, &tag)
}
// InvalidTagNumber returns a validation error for messages with invalid tags.
func InvalidTagNumber(tag Tag) MessageRejectError {
return NewMessageRejectError("Invalid tag number", rejectReasonInvalidTagNumber, &tag)
}
// compIDProblem creates a reject for msg where msg has invalid comp id values.
func compIDProblem() MessageRejectError {
return NewMessageRejectError("CompID problem", rejectReasonCompIDProblem, nil)
}
// sendingTimeAccuracyProblem creates a reject for a msg with stale or invalid sending time.
func sendingTimeAccuracyProblem() MessageRejectError {
return NewMessageRejectError("SendingTime accuracy problem", rejectReasonSendingTimeAccuracyProblem, nil)
}