mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 01:07:18 +03:00
Cleanup GlobalKey use (#19027)
* Cleanup GlobalKey use * With canton one line fix * Update with review comments * Add packageName to GlobalKey.toString
This commit is contained in:
parent
52c63cdfde
commit
05212c9fd4
@ -2448,14 +2448,11 @@ class EngineTestHelpers(majorLanguageVersion: LanguageMajorVersion) {
|
||||
// non-dev dar
|
||||
s"daml-lf/engine/BasicTests-v${majorLanguageVersion.pretty}dev.dar"
|
||||
)
|
||||
val basicTestsHashPkgName =
|
||||
if (GlobalKey.useDummyHashPackageName) GlobalKey.dummyHashPackageName else basicTestsPkg.name
|
||||
val basicTestsHashPkgName: PackageName = basicTestsPkg.name
|
||||
|
||||
val basicTestsSignatures: PackageInterface =
|
||||
language.PackageInterface(Map(basicTestsPkgId -> basicTestsPkg))
|
||||
|
||||
val basicUseSharedKeys: Boolean = true
|
||||
|
||||
val party: Ref.IdString.Party = Party.assertFromString("Party")
|
||||
val alice: Ref.IdString.Party = Party.assertFromString("Alice")
|
||||
val bob: Ref.IdString.Party = Party.assertFromString("Bob")
|
||||
|
@ -5,7 +5,7 @@ package com.daml.lf
|
||||
package engine
|
||||
|
||||
import com.daml.lf.crypto.Hash
|
||||
import com.daml.lf.data.Ref.Party
|
||||
import com.daml.lf.data.Ref.{PackageRef, Party}
|
||||
import com.daml.lf.data.{Bytes, FrontStack, ImmArray, Ref}
|
||||
import com.daml.lf.command.ApiCommand
|
||||
import com.daml.lf.language.{Ast, LanguageMajorVersion, LanguageVersion}
|
||||
@ -20,7 +20,6 @@ import com.daml.lf.testing.parser.ParserParameters
|
||||
import com.daml.lf.transaction.test.TransactionBuilder.Implicits.{defaultPackageId => _, _}
|
||||
import com.daml.lf.value.Value
|
||||
import com.daml.lf.speedy.Compiler
|
||||
import com.daml.lf.transaction.GlobalKey
|
||||
|
||||
class PreprocessorSpecV2 extends PreprocessorSpec(LanguageMajorVersion.V2)
|
||||
|
||||
@ -335,7 +334,7 @@ final class PreprocessorSpecHelpers(majorLanguageVersion: LanguageMajorVersion)
|
||||
crypto.Hash.hashPrivateKey("test-contract-id"),
|
||||
Bytes.assertFromString("deadbeef"),
|
||||
)
|
||||
val pkgRef = Ref.PackageRef.Name(pkgName)
|
||||
val pkgRef: PackageRef.Name = Ref.PackageRef.Name(pkgName)
|
||||
val withoutKeyTmplId: Ref.TypeConName = Ref.Identifier.assertFromString("-pkgId-:Mod:WithoutKey")
|
||||
val withoutKeyTmplRef: Ref.TypeConRef = Ref.TypeConRef(pkgRef, withoutKeyTmplId.qualifiedName)
|
||||
val withKeyTmplId: Ref.TypeConName = Ref.Identifier.assertFromString("-pkgId-:Mod:WithKey")
|
||||
@ -347,14 +346,9 @@ final class PreprocessorSpecHelpers(majorLanguageVersion: LanguageMajorVersion)
|
||||
None -> Value.ValueList(FrontStack.from(ImmArray(ValueParty(alice)))),
|
||||
),
|
||||
)
|
||||
val keyHash: Hash = crypto.Hash.assertHashContractKey(withKeyTmplId, pkgName, key)
|
||||
|
||||
val basicTestsHashPkgName =
|
||||
if (GlobalKey.useDummyHashPackageName) GlobalKey.dummyHashPackageName else pkgName
|
||||
|
||||
val keyHash: Hash =
|
||||
crypto.Hash.assertHashContractKey(withKeyTmplId, basicTestsHashPkgName, key)
|
||||
|
||||
val choiceId = Ref.Name.assertFromString("Noop")
|
||||
val choiceId: Ref.Name = Ref.Name.assertFromString("Noop")
|
||||
|
||||
def buildDisclosedContract(
|
||||
contractId: ContractId = contractId,
|
||||
|
@ -96,7 +96,7 @@ private[lf] class ExplicitDisclosureLib(majorLanguageVersion: LanguageMajorVersi
|
||||
val caveTemplateId: Ref.Identifier = Ref.Identifier.assertFromString("-pkgId-:TestMod:Cave")
|
||||
val caveTemplateType: Ref.TypeConName = Ref.TypeConName.assertFromString("-pkgId-:TestMod:Cave")
|
||||
val keyType: Ref.TypeConName = Ref.TypeConName.assertFromString("-pkgId-:TestMod:Key")
|
||||
val contractKey: GlobalKey = buildContractKey(maintainerParty, somePackageName)
|
||||
val contractKey: GlobalKey = buildContractKey(maintainerParty, pkg.name)
|
||||
val contractSStructKey: SValue =
|
||||
SValue.SStruct(
|
||||
fieldNames =
|
||||
|
@ -7,7 +7,6 @@ package transaction
|
||||
import com.daml.lf.crypto.Hash
|
||||
import com.daml.lf.data.Ref
|
||||
import com.daml.lf.data.Ref.{Party, TypeConName}
|
||||
import com.daml.lf.transaction.GlobalKey.dummyHashPackageName
|
||||
import com.daml.lf.value.Value
|
||||
|
||||
/** Useful in various circumstances -- basically this is what a ledger implementation must use as
|
||||
@ -30,21 +29,15 @@ final class GlobalKey private (
|
||||
|
||||
override def hashCode(): Int = hash.hashCode()
|
||||
|
||||
override def toString: String = s"GlobalKey($templateId, $key)"
|
||||
override def toString: String = s"GlobalKey($templateId, $packageName, $key)"
|
||||
}
|
||||
|
||||
object GlobalKey {
|
||||
|
||||
// #TODO(18828) Use dummy package name until all call sites are updated
|
||||
private[lf] val useDummyHashPackageName = true
|
||||
private[lf] val dummyHashPackageName =
|
||||
Ref.PackageName.assertFromString("dummy-package-name")
|
||||
|
||||
def assertWithRenormalizedValue(key: GlobalKey, value: Value): GlobalKey = {
|
||||
val hashPackageName = if (useDummyHashPackageName) dummyHashPackageName else key.packageName
|
||||
if (
|
||||
key.key != value &&
|
||||
Hash.assertHashContractKey(key.templateId, hashPackageName, value) != key.hash
|
||||
Hash.assertHashContractKey(key.templateId, key.packageName, value) != key.hash
|
||||
) {
|
||||
throw new IllegalArgumentException(
|
||||
s"Hash must not change as a result of value renormalization key=$key, value=$value"
|
||||
@ -59,18 +52,17 @@ object GlobalKey {
|
||||
def build(
|
||||
templateId: TypeConName,
|
||||
key: Value,
|
||||
packageName: Ref.PackageName = dummyHashPackageName,
|
||||
packageName: Ref.PackageName,
|
||||
): Either[crypto.Hash.HashingError, GlobalKey] = {
|
||||
val hashPackageName = if (useDummyHashPackageName) dummyHashPackageName else packageName
|
||||
crypto.Hash
|
||||
.hashContractKey(templateId, hashPackageName, key)
|
||||
.hashContractKey(templateId, packageName, key)
|
||||
.map(new GlobalKey(templateId, packageName, key, _))
|
||||
}
|
||||
|
||||
def assertBuild(
|
||||
templateId: TypeConName,
|
||||
key: Value,
|
||||
packageName: Ref.PackageName = dummyHashPackageName,
|
||||
packageName: Ref.PackageName,
|
||||
): GlobalKey = {
|
||||
data.assertRight(build(templateId, key, packageName).left.map(_.msg))
|
||||
}
|
||||
@ -93,7 +85,7 @@ object GlobalKeyWithMaintainers {
|
||||
templateId: TypeConName,
|
||||
value: Value,
|
||||
maintainers: Set[Party],
|
||||
packageName: Ref.PackageName = dummyHashPackageName,
|
||||
packageName: Ref.PackageName,
|
||||
): GlobalKeyWithMaintainers =
|
||||
data.assertRight(build(templateId, value, maintainers, packageName).left.map(_.msg))
|
||||
|
||||
@ -101,7 +93,7 @@ object GlobalKeyWithMaintainers {
|
||||
templateId: TypeConName,
|
||||
value: Value,
|
||||
maintainers: Set[Party],
|
||||
packageName: Ref.PackageName = dummyHashPackageName,
|
||||
packageName: Ref.PackageName,
|
||||
): Either[Hash.HashingError, GlobalKeyWithMaintainers] =
|
||||
GlobalKey.build(templateId, value, packageName).map(GlobalKeyWithMaintainers(_, maintainers))
|
||||
}
|
||||
|
@ -61,20 +61,6 @@ object GrpcErrorParser {
|
||||
.lift(resourceDetails)
|
||||
.getOrElse(new SubmitError.TruncatedError(classNameOf[A], message))
|
||||
|
||||
// Only needed until canton is updated to provide package names
|
||||
def casePnErr[A <: SubmitError: ClassTag](
|
||||
handler: PartialFunction[Seq[(ErrorResource, String)], A]
|
||||
): SubmitError = {
|
||||
val hasPn = resourceDetails.exists({ case (er, _) => er == ErrorResource.PackageName })
|
||||
val pnResourceDetails =
|
||||
if (hasPn) resourceDetails
|
||||
else
|
||||
resourceDetails :+ ErrorResource.PackageName -> GlobalKey.dummyHashPackageName
|
||||
handler
|
||||
.lift(pnResourceDetails)
|
||||
.getOrElse(new SubmitError.TruncatedError(classNameOf[A], message))
|
||||
}
|
||||
|
||||
errorCode match {
|
||||
case "CONTRACT_NOT_FOUND" =>
|
||||
caseErr {
|
||||
@ -96,7 +82,7 @@ object GrpcErrorParser {
|
||||
)
|
||||
}
|
||||
case "CONTRACT_KEY_NOT_FOUND" =>
|
||||
casePnErr {
|
||||
caseErr {
|
||||
case Seq(
|
||||
(ErrorResource.TemplateId, tid),
|
||||
(ErrorResource.ContractKey, decodeValue.unlift(key)),
|
||||
@ -117,7 +103,7 @@ object GrpcErrorParser {
|
||||
)
|
||||
}
|
||||
case "DISCLOSED_CONTRACT_KEY_HASHING_ERROR" =>
|
||||
casePnErr {
|
||||
caseErr {
|
||||
case Seq(
|
||||
(ErrorResource.TemplateId, tid),
|
||||
(ErrorResource.ContractId, cid),
|
||||
@ -134,7 +120,7 @@ object GrpcErrorParser {
|
||||
)
|
||||
}
|
||||
case "DUPLICATE_CONTRACT_KEY" =>
|
||||
casePnErr {
|
||||
caseErr {
|
||||
case Seq(
|
||||
(ErrorResource.TemplateId, tid),
|
||||
(ErrorResource.ContractKey, decodeValue.unlift(key)),
|
||||
@ -163,7 +149,7 @@ object GrpcErrorParser {
|
||||
case _ => SubmitError.LocalVerdictLockedContracts(Seq())
|
||||
}
|
||||
case "INCONSISTENT_CONTRACT_KEY" =>
|
||||
casePnErr {
|
||||
caseErr {
|
||||
|
||||
case Seq(
|
||||
(ErrorResource.TemplateId, tid),
|
||||
@ -199,7 +185,7 @@ object GrpcErrorParser {
|
||||
SubmitError.CreateEmptyContractKeyMaintainers(Identifier.assertFromString(tid), arg)
|
||||
}
|
||||
case "FETCH_EMPTY_CONTRACT_KEY_MAINTAINERS" =>
|
||||
casePnErr {
|
||||
caseErr {
|
||||
case Seq(
|
||||
(ErrorResource.TemplateId, tid),
|
||||
(ErrorResource.ContractKey, decodeValue.unlift(key)),
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,15 +12,7 @@ da_scala_library(
|
||||
tags = ["maven_coordinates=com.daml:ledger-api-errors:__VERSION__"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//canton:ledger_api_proto_scala",
|
||||
"//daml-lf/data",
|
||||
"//daml-lf/engine",
|
||||
"//daml-lf/language",
|
||||
"//daml-lf/transaction",
|
||||
"//daml-lf/validation",
|
||||
"//ledger/error",
|
||||
"@maven//:com_google_api_grpc_proto_google_common_protos",
|
||||
"@maven//:io_grpc_grpc_api",
|
||||
"@maven//:org_slf4j_slf4j_api",
|
||||
],
|
||||
)
|
||||
|
@ -1,12 +1,6 @@
|
||||
# Ledger error definitions
|
||||
|
||||
Home to error definitions commonly reported via the Ledger API server.
|
||||
These errors are generic wrt to the ledger backend used by the participant server.
|
||||
Error codes in the ledger-api-errors package were duplicates of those in the Canton repository and are no longer
|
||||
used or needed.
|
||||
|
||||
## Daml-LF dependencies
|
||||
|
||||
Multiple error definitions depend on Daml LF types whose Bazel targets
|
||||
pull in unrelated dependencies, such as the Daml engine.
|
||||
|
||||
**TODO (https://github.com/digital-asset/daml/issues/15453):** Extract Daml-LF interface types to separate package
|
||||
in order to decouple the error definitions from the Daml engine.
|
||||
This entire module is set for removal as part of https://github.com/DACH-NY/canton/issues/18444
|
||||
|
@ -1,72 +0,0 @@
|
||||
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.error.definitions
|
||||
|
||||
import com.daml.error.ErrorCode.LoggedApiException
|
||||
import com.daml.error._
|
||||
import com.daml.error.definitions.ErrorGroups.ParticipantErrorGroup.IndexErrorGroup
|
||||
|
||||
@Explanation("Errors raised by the Participant Index persistence layer.")
|
||||
object IndexErrors extends IndexErrorGroup {
|
||||
object DatabaseErrors extends DatabaseErrorGroup {
|
||||
@Explanation(
|
||||
"This error occurs if a transient error arises when executing a query against the index database."
|
||||
)
|
||||
@Resolution("Re-submit the request.")
|
||||
object SqlTransientError
|
||||
extends ErrorCode(
|
||||
id = "INDEX_DB_SQL_TRANSIENT_ERROR",
|
||||
ErrorCategory.TransientServerFailure,
|
||||
) {
|
||||
case class Reject(throwable: Throwable)(implicit
|
||||
val loggingContext: ContextualizedErrorLogger
|
||||
) extends DbError(
|
||||
cause =
|
||||
s"Processing the request failed due to a transient database error: ${throwable.getMessage}",
|
||||
throwableO = Some(throwable),
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"This error occurs if a non-transient error arises when executing a query against the index database."
|
||||
)
|
||||
@Resolution("Contact the participant operator.")
|
||||
object SqlNonTransientError
|
||||
extends ErrorCode(
|
||||
id = "INDEX_DB_SQL_NON_TRANSIENT_ERROR",
|
||||
ErrorCategory.SystemInternalAssumptionViolated,
|
||||
) {
|
||||
case class Reject(throwable: Throwable)(implicit
|
||||
val loggingContext: ContextualizedErrorLogger
|
||||
) extends DbError(
|
||||
cause =
|
||||
s"Processing the request failed due to a non-transient database error: ${throwable.getMessage}",
|
||||
throwableO = Some(throwable),
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Decorator that returns a specialized StatusRuntimeException (IndexDbException)
|
||||
// that can be used for precise matching of persistence exceptions (e.g. for index initialization failures that need retrying).
|
||||
// Without this specialization, internal errors just appear as StatusRuntimeExceptions (see INDEX_DB_SQL_NON_TRANSIENT_ERROR)
|
||||
// without any marker, impeding us to assert whether they are emitted by the persistence layer or not.
|
||||
abstract class DbError(
|
||||
override val cause: String,
|
||||
override val throwableO: Option[Throwable] = None,
|
||||
)(implicit
|
||||
code: ErrorCode,
|
||||
loggingContext: ContextualizedErrorLogger,
|
||||
) extends DamlErrorWithDefiniteAnswer(cause, throwableO) {
|
||||
|
||||
override def asGrpcError: IndexDbException = {
|
||||
val err = super.asGrpcError
|
||||
IndexDbException(err.getStatus, err.getTrailers)
|
||||
}
|
||||
}
|
||||
|
||||
case class IndexDbException(status: io.grpc.Status, metadata: io.grpc.Metadata)
|
||||
extends LoggedApiException(status, metadata)
|
||||
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.error.definitions
|
||||
|
||||
import com.daml.error._
|
||||
import com.daml.error.definitions.ErrorGroups.ParticipantErrorGroup.LedgerApiErrorGroup
|
||||
import com.daml.lf.engine.Error.Validation.ReplayMismatch
|
||||
import com.daml.lf.engine.{Error => LfError}
|
||||
|
||||
@Explanation(
|
||||
"Errors raised by or forwarded by the Ledger API."
|
||||
)
|
||||
object LedgerApiErrors extends LedgerApiErrorGroup {
|
||||
|
||||
val Admin: groups.AdminServices.type = groups.AdminServices
|
||||
val CommandExecution: groups.CommandExecution.type = groups.CommandExecution
|
||||
val AuthorizationChecks: groups.AuthorizationChecks.type = groups.AuthorizationChecks
|
||||
val ConsistencyErrors: groups.ConsistencyErrors.type = groups.ConsistencyErrors
|
||||
val RequestValidation: groups.RequestValidation.type = groups.RequestValidation
|
||||
val WriteServiceRejections: groups.WriteServiceRejections.type = groups.WriteServiceRejections
|
||||
|
||||
val EarliestOffsetMetadataKey = "earliest_offset"
|
||||
|
||||
@Explanation("""This error occurs if there was an unexpected error in the Ledger API.""")
|
||||
@Resolution("Contact support.")
|
||||
object InternalError
|
||||
extends ErrorCode(
|
||||
id = "LEDGER_API_INTERNAL_ERROR",
|
||||
ErrorCategory.SystemInternalAssumptionViolated,
|
||||
) {
|
||||
|
||||
case class Generic(
|
||||
message: String,
|
||||
override val throwableO: Option[Throwable] = None,
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = message,
|
||||
extraContext = Map("throwableO" -> throwableO.toString),
|
||||
)
|
||||
|
||||
case class Preprocessing(
|
||||
err: LfError.Preprocessing.Internal
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(cause = err.message)
|
||||
|
||||
case class Validation(reason: ReplayMismatch)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = s"Observed un-expected replay mismatch: $reason"
|
||||
)
|
||||
|
||||
case class Interpretation(
|
||||
where: String,
|
||||
message: String,
|
||||
detailMessage: Option[String],
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = s"Daml-Engine interpretation failed with internal error: $where / $message",
|
||||
extraContext = Map("detailMessage" -> detailMessage),
|
||||
)
|
||||
|
||||
case class VersionService(message: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(cause = message)
|
||||
|
||||
case class Buffer(message: String, override val throwableO: Option[Throwable])(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(cause = message, throwableO = throwableO)
|
||||
}
|
||||
}
|
@ -1,141 +0,0 @@
|
||||
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.error.definitions
|
||||
|
||||
import com.daml.error._
|
||||
import com.daml.lf.data.Ref
|
||||
import com.daml.lf.data.Ref.PackageId
|
||||
import com.daml.lf.validation
|
||||
|
||||
@Explanation(
|
||||
"Errors raised by the Package Management Service on package uploads."
|
||||
)
|
||||
object PackageServiceError extends LedgerApiErrors.PackageServiceErrorGroup {
|
||||
@Explanation("Package parsing errors raised during package upload.")
|
||||
object Reading extends ErrorGroup {
|
||||
|
||||
@Explanation("""This error indicates that the supplied dar file was invalid.""")
|
||||
@Resolution("Inspect the error message for details and contact support.")
|
||||
object InvalidDar
|
||||
extends ErrorCode(id = "INVALID_DAR", ErrorCategory.InvalidIndependentOfSystemState) {
|
||||
final case class Error(entries: Seq[String], throwable: Throwable)(implicit
|
||||
val loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause = "Dar file is corrupt",
|
||||
throwableO = Some(throwable),
|
||||
extraContext = Map(
|
||||
"entries" -> entries,
|
||||
"throwable" -> throwable,
|
||||
),
|
||||
)
|
||||
}
|
||||
@Explanation("""This error indicates that the supplied zipped dar file was invalid.""")
|
||||
@Resolution("Inspect the error message for details and contact support.")
|
||||
object InvalidZipEntry
|
||||
extends ErrorCode(id = "INVALID_ZIP_ENTRY", ErrorCategory.InvalidIndependentOfSystemState) {
|
||||
final case class Error(name: String, entries: Seq[String])(implicit
|
||||
val loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause = "Dar zip file is corrupt",
|
||||
extraContext = Map(
|
||||
"name" -> name,
|
||||
"entries" -> entries,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation("""This error indicates that the supplied zipped dar is regarded as zip-bomb.""")
|
||||
@Resolution("Inspect the dar and contact support.")
|
||||
object ZipBomb
|
||||
extends ErrorCode(id = "ZIP_BOMB", ErrorCategory.InvalidIndependentOfSystemState) {
|
||||
final case class Error(msg: String)(implicit
|
||||
val loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause = "Dar zip file seems to be a zip bomb.",
|
||||
extraContext = Map("msg" -> msg),
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Explanation("""This error indicates an internal issue within the package service.""")
|
||||
@Resolution("Inspect the error message and contact support.")
|
||||
object InternalError
|
||||
extends ErrorCode(
|
||||
id = "PACKAGE_SERVICE_INTERNAL_ERROR",
|
||||
ErrorCategory.SystemInternalAssumptionViolated,
|
||||
) {
|
||||
final case class Validation(nameOfFunc: String, msg: String, detailMsg: String = "")(implicit
|
||||
val loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause = "Internal package validation error.",
|
||||
extraContext = Map(
|
||||
"nameOfFunc" -> nameOfFunc,
|
||||
"msg" -> msg,
|
||||
"detailMsg" -> detailMsg,
|
||||
),
|
||||
)
|
||||
final case class Error(missing: Set[PackageId])(implicit
|
||||
val loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause = "Failed to resolve package ids locally.",
|
||||
extraContext = Map("missing" -> missing),
|
||||
)
|
||||
final case class Generic(reason: String)(implicit
|
||||
val loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause = "Generic error (please check the reason string).",
|
||||
extraContext = Map("reason" -> reason),
|
||||
)
|
||||
final case class Unhandled(throwable: Throwable)(implicit
|
||||
val loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause = "Failed with an unknown error cause",
|
||||
throwableO = Some(throwable),
|
||||
extraContext = Map("throwable" -> throwable),
|
||||
)
|
||||
}
|
||||
|
||||
object Validation {
|
||||
|
||||
@Explanation("""This error indicates that the validation of the uploaded dar failed.""")
|
||||
@Resolution("Inspect the error message and contact support.")
|
||||
object ValidationError
|
||||
extends ErrorCode(
|
||||
id = "DAR_VALIDATION_ERROR",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
final case class Error(validationError: validation.ValidationError)(implicit
|
||||
val loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause = "Package validation failed.",
|
||||
extraContext = Map("validationError" -> validationError),
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error indicates that the uploaded Dar is broken because it is missing internal dependencies."""
|
||||
)
|
||||
@Resolution("Contact the supplier of the Dar.")
|
||||
object SelfConsistency
|
||||
extends ErrorCode(
|
||||
id = "DAR_NOT_SELF_CONSISTENT",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
final case class Error(
|
||||
packageIds: Set[Ref.PackageId],
|
||||
missingDependencies: Set[Ref.PackageId],
|
||||
)(implicit
|
||||
val loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause =
|
||||
"The set of packages in the dar is not self-consistent and is missing dependencies",
|
||||
extraContext = Map(
|
||||
"packageIds" -> packageIds,
|
||||
"missingDependencies" -> missingDependencies,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.error.definitions.groups
|
||||
|
||||
import com.daml.error.definitions.{LedgerApiErrors}
|
||||
import com.daml.error.definitions.groups
|
||||
import com.daml.error.{
|
||||
ContextualizedErrorLogger,
|
||||
DamlErrorWithDefiniteAnswer,
|
||||
ErrorCategory,
|
||||
ErrorCode,
|
||||
Explanation,
|
||||
Resolution,
|
||||
}
|
||||
|
||||
@Explanation("Errors raised by Ledger API admin services.")
|
||||
object AdminServices extends LedgerApiErrors.AdminServicesErrorGroup {
|
||||
|
||||
val UserManagement: groups.UserManagementServiceErrorGroup.type =
|
||||
groups.UserManagementServiceErrorGroup
|
||||
val IdentityProviderConfig: groups.IdentityProviderConfigServiceErrorGroup.type =
|
||||
groups.IdentityProviderConfigServiceErrorGroup
|
||||
val PartyManagement: groups.PartyManagementServiceErrorGroup.type =
|
||||
groups.PartyManagementServiceErrorGroup
|
||||
|
||||
@Explanation("This rejection is given when a new configuration is rejected.")
|
||||
@Resolution("Fetch newest configuration and/or retry.")
|
||||
object ConfigurationEntryRejected
|
||||
extends ErrorCode(
|
||||
id = "CONFIGURATION_ENTRY_REJECTED",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateOther,
|
||||
) {
|
||||
|
||||
case class Reject(_message: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = _message
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.error.definitions.groups
|
||||
|
||||
import com.daml.error.definitions.{LedgerApiErrors}
|
||||
import com.daml.error.{
|
||||
ContextualizedErrorLogger,
|
||||
DamlErrorWithDefiniteAnswer,
|
||||
ErrorCategory,
|
||||
ErrorCategoryRetry,
|
||||
ErrorCode,
|
||||
Explanation,
|
||||
Resolution,
|
||||
}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
@Explanation("Authentication and authorization errors.")
|
||||
object AuthorizationChecks extends LedgerApiErrors.AuthorizationChecks {
|
||||
|
||||
@Explanation("""The stream was aborted because the authenticated user's rights changed,
|
||||
|and the user might thus no longer be authorized to this stream.
|
||||
|""")
|
||||
@Resolution(
|
||||
"The application should automatically retry fetching the stream. It will either succeed, or fail with an explicit denial of authentication or permission."
|
||||
)
|
||||
object StaleUserManagementBasedStreamClaims
|
||||
extends ErrorCode(
|
||||
id = "STALE_STREAM_AUTHORIZATION",
|
||||
ErrorCategory.ContentionOnSharedResources,
|
||||
) {
|
||||
case class Reject()(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer("Stale stream authorization. Retry quickly.") {
|
||||
override def retryable: Option[ErrorCategoryRetry] = Some(
|
||||
ErrorCategoryRetry(duration = 0.seconds)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This rejection is given if the submitted command does not contain a JWT token on a participant enforcing JWT authentication."""
|
||||
)
|
||||
@Resolution(
|
||||
"Ask your participant operator to provide you with an appropriate JWT token."
|
||||
)
|
||||
object Unauthenticated
|
||||
extends ErrorCode(
|
||||
id = "UNAUTHENTICATED",
|
||||
ErrorCategory.AuthInterceptorInvalidAuthenticationCredentials,
|
||||
) {
|
||||
case class MissingJwtToken()(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = "The command is missing a (valid) JWT token"
|
||||
)
|
||||
|
||||
case class UserBasedAuthenticationIsDisabled()(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = "User based authentication is disabled."
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation("An internal system authorization error occurred.")
|
||||
@Resolution("Contact the participant operator.")
|
||||
object InternalAuthorizationError
|
||||
extends ErrorCode(
|
||||
id = "INTERNAL_AUTHORIZATION_ERROR",
|
||||
ErrorCategory.SystemInternalAssumptionViolated,
|
||||
) {
|
||||
case class Reject(message: String, throwable: Throwable)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = message,
|
||||
throwableO = Some(throwable),
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This rejection is given if the supplied authorization token is not sufficient for the intended command.
|
||||
|The exact reason is logged on the participant, but not given to the user for security reasons."""
|
||||
)
|
||||
@Resolution(
|
||||
"Inspect your command and your token or ask your participant operator for an explanation why this command failed."
|
||||
)
|
||||
object PermissionDenied
|
||||
extends ErrorCode(id = "PERMISSION_DENIED", ErrorCategory.InsufficientPermission) {
|
||||
case class Reject(override val cause: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause =
|
||||
s"The provided authorization token is not sufficient to authorize the intended command: $cause"
|
||||
)
|
||||
}
|
||||
}
|
@ -1,475 +0,0 @@
|
||||
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.error.definitions.groups
|
||||
|
||||
import com.daml.error.definitions.{LedgerApiErrors}
|
||||
import com.daml.error.{
|
||||
ContextualizedErrorLogger,
|
||||
DamlErrorWithDefiniteAnswer,
|
||||
ErrorCategory,
|
||||
ErrorCode,
|
||||
ErrorGroup,
|
||||
ErrorResource,
|
||||
Explanation,
|
||||
Resolution,
|
||||
}
|
||||
import com.daml.lf.data.Ref.Identifier
|
||||
import com.daml.lf.engine.{Error => LfError}
|
||||
import com.daml.lf.interpretation.{Error => LfInterpretationError}
|
||||
import com.daml.lf.language.Ast
|
||||
import com.daml.lf.transaction.{GlobalKey, TransactionVersion}
|
||||
import com.daml.lf.value.{Value, ValueCoder}
|
||||
|
||||
@Explanation(
|
||||
"Errors raised during the command execution phase of the command submission evaluation."
|
||||
)
|
||||
object CommandExecution extends ErrorGroup()(LedgerApiErrors.errorClass) {
|
||||
def encodeValue(v: Value): Either[ValueCoder.EncodeError, String] =
|
||||
ValueCoder
|
||||
.encodeValue(TransactionVersion.VDev, v)
|
||||
.map(_.toStringUtf8)
|
||||
|
||||
def withEncodedValue(
|
||||
v: Value
|
||||
)(
|
||||
f: String => Seq[(ErrorResource, String)]
|
||||
)(implicit loggingContext: ContextualizedErrorLogger): Seq[(ErrorResource, String)] =
|
||||
encodeValue(v).fold(
|
||||
{ case ValueCoder.EncodeError(msg) =>
|
||||
loggingContext.error(msg)
|
||||
Seq.empty
|
||||
},
|
||||
f,
|
||||
)
|
||||
|
||||
@Explanation(
|
||||
"Errors raised during command conversion to the internal data representation."
|
||||
)
|
||||
object Preprocessing extends ErrorGroup {
|
||||
@Explanation("""This error occurs if a command fails during interpreter pre-processing.""")
|
||||
@Resolution("Inspect error details and correct your application.")
|
||||
object PreprocessingFailed
|
||||
extends ErrorCode(
|
||||
id = "COMMAND_PREPROCESSING_FAILED",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
final case class Reject(
|
||||
err: LfError.Preprocessing.Error
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = err.message
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"Errors raised during the command interpretation phase of the command submission evaluation."
|
||||
)
|
||||
object Interpreter extends ErrorGroup {
|
||||
@Explanation(
|
||||
"""This error occurs if an exercise or fetch happens on a transaction-locally consumed contract."""
|
||||
)
|
||||
@Resolution("This error indicates an application error.")
|
||||
object ContractNotActive
|
||||
extends ErrorCode(
|
||||
id = "CONTRACT_NOT_ACTIVE",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceMissing,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val cause: String,
|
||||
err: LfInterpretationError.ContractNotActive,
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
(ErrorResource.TemplateId, err.templateId.toString),
|
||||
(ErrorResource.ContractId, err.coid.coid),
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Explanation("Errors raised in lookups during the command interpretation phase.")
|
||||
object LookupErrors extends ErrorGroup {
|
||||
@Explanation(
|
||||
"""This error occurs if the Daml engine interpreter cannot resolve a contract key to an active contract. This
|
||||
|can be caused by either the contract key not being known to the participant, or not being known to
|
||||
|the submitting parties or the contract representing an already archived key."""
|
||||
)
|
||||
@Resolution("This error type occurs if there is contention on a contract.")
|
||||
object ContractKeyNotFound
|
||||
extends ErrorCode(
|
||||
id = "CONTRACT_KEY_NOT_FOUND",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceMissing,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val cause: String,
|
||||
key: GlobalKey,
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] =
|
||||
withEncodedValue(key.key) { encodedKey =>
|
||||
Seq(
|
||||
(ErrorResource.TemplateId, key.templateId.toString),
|
||||
(ErrorResource.ContractKey, encodedKey),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation("""This error occurs if a Daml transaction fails due to an authorization error.
|
||||
|An authorization means that the Daml transaction computed a different set of required submitters than
|
||||
|you have provided during the submission as `actAs` parties.""")
|
||||
@Resolution("This error type occurs if there is an application error.")
|
||||
object AuthorizationError
|
||||
extends ErrorCode(
|
||||
id = "DAML_AUTHORIZATION_ERROR",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
|
||||
final case class Reject(override val cause: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error occurs if a user attempts to provide a key hash for a disclosed contract which we have already cached to be different."""
|
||||
)
|
||||
@Resolution(
|
||||
"Ensure the contract ID and contract payload you have provided in your disclosed contract is correct."
|
||||
)
|
||||
object DisclosedContractKeyHashingError
|
||||
extends ErrorCode(
|
||||
id = "DISCLOSED_CONTRACT_KEY_HASHING_ERROR",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateOther,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val cause: String,
|
||||
err: LfInterpretationError.DisclosedContractKeyHashingError,
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
) {
|
||||
|
||||
override def resources: Seq[(ErrorResource, String)] =
|
||||
withEncodedValue(err.key.key) { encodedKey =>
|
||||
Seq(
|
||||
(ErrorResource.TemplateId, err.key.templateId.toString),
|
||||
(ErrorResource.ContractId, err.coid.coid),
|
||||
(ErrorResource.ContractKey, encodedKey),
|
||||
(ErrorResource.ContractKeyHash, err.declaredHash.toString),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def getTypeIdentifier(t: Ast.Type): Option[Identifier] =
|
||||
t match {
|
||||
case Ast.TTyCon(ty) => Some(ty)
|
||||
case _ => None
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error occurs when a user throws an error and does not catch it with try-catch."""
|
||||
)
|
||||
@Resolution(
|
||||
"Either your error handling in a choice body is insufficient, or you are using a contract incorrectly."
|
||||
)
|
||||
object UnhandledException
|
||||
extends ErrorCode(
|
||||
id = "UNHANDLED_EXCEPTION",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateOther,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val cause: String,
|
||||
err: LfInterpretationError.UnhandledException,
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] =
|
||||
withEncodedValue(err.value) { encodedValue =>
|
||||
getTypeIdentifier(err.exceptionType)
|
||||
.map(ty =>
|
||||
Seq(
|
||||
(ErrorResource.ExceptionType, ty.toString),
|
||||
(ErrorResource.ExceptionValue, encodedValue),
|
||||
)
|
||||
)
|
||||
.getOrElse(Nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error occurs when a contract's pre-condition (the ensure clause) is violated on contract creation."""
|
||||
)
|
||||
@Resolution(
|
||||
"Ensure the contract argument you are passing into your create doesn't violate the conditions of the contract."
|
||||
)
|
||||
object TemplatePreconditionViolated
|
||||
extends ErrorCode(
|
||||
id = "TEMPLATE_PRECONDITION_VIOLATED",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val cause: String
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
) {}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error occurs when you try to create a contract that has a key, but with empty maintainers."""
|
||||
)
|
||||
@Resolution(
|
||||
"Check the definition of the contract key's maintainers, and ensure this list won't be empty given your creation arguments."
|
||||
)
|
||||
object CreateEmptyContractKeyMaintainers
|
||||
extends ErrorCode(
|
||||
id = "CREATE_EMPTY_CONTRACT_KEY_MAINTAINERS",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val cause: String,
|
||||
err: LfInterpretationError.CreateEmptyContractKeyMaintainers,
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
) {
|
||||
|
||||
override def resources: Seq[(ErrorResource, String)] =
|
||||
withEncodedValue(err.arg) { encodedArg =>
|
||||
Seq(
|
||||
(ErrorResource.TemplateId, err.templateId.toString),
|
||||
(ErrorResource.ContractArg, encodedArg),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error occurs when you try to fetch a contract by key, but that key would have empty maintainers."""
|
||||
)
|
||||
@Resolution(
|
||||
"Check the definition of the contract key's maintainers, and ensure this list won't be empty given the contract key you are fetching."
|
||||
)
|
||||
object FetchEmptyContractKeyMaintainers
|
||||
extends ErrorCode(
|
||||
id = "FETCH_EMPTY_CONTRACT_KEY_MAINTAINERS",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val cause: String,
|
||||
err: LfInterpretationError.FetchEmptyContractKeyMaintainers,
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
) {
|
||||
|
||||
override def resources: Seq[(ErrorResource, String)] =
|
||||
withEncodedValue(err.key) { encodedKey =>
|
||||
Seq(
|
||||
(ErrorResource.TemplateId, err.templateId.toString),
|
||||
(ErrorResource.ContractKey, encodedKey),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error occurs when you try to fetch/use a contract in some way with a contract ID that doesn't match the template type on the ledger."""
|
||||
)
|
||||
@Resolution(
|
||||
"Ensure the contract IDs you are using are of the type we expect on the ledger. Avoid unsafely coercing contract IDs."
|
||||
)
|
||||
object WronglyTypedContract
|
||||
extends ErrorCode(
|
||||
id = "WRONGLY_TYPED_CONTRACT",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateOther,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val cause: String,
|
||||
err: LfInterpretationError.WronglyTypedContract,
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
) {
|
||||
|
||||
override def resources: Seq[(ErrorResource, String)] =
|
||||
Seq(
|
||||
(ErrorResource.ContractId, err.coid.coid),
|
||||
(ErrorResource.TemplateId, err.expected.toString),
|
||||
(ErrorResource.TemplateId, err.actual.toString),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error occurs when you try to coerce/use a contract via an interface that it does not implement."""
|
||||
)
|
||||
@Resolution(
|
||||
"Ensure the contract you are calling does implement the interface you are using to do so. Avoid writing LF/low-level interface implementation classes manually."
|
||||
)
|
||||
object ContractDoesNotImplementInterface
|
||||
extends ErrorCode(
|
||||
id = "CONTRACT_DOES_NOT_IMPLEMENT_INTERFACE",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val cause: String,
|
||||
err: LfInterpretationError.ContractDoesNotImplementInterface,
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
) {
|
||||
|
||||
override def resources: Seq[(ErrorResource, String)] =
|
||||
Seq(
|
||||
(ErrorResource.ContractId, err.coid.coid),
|
||||
(ErrorResource.TemplateId, err.templateId.toString),
|
||||
(ErrorResource.InterfaceId, err.interfaceId.toString),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error occurs when you try to create/use a contract that does not implement the requiring interfaces of some other interface that it does implement."""
|
||||
)
|
||||
@Resolution(
|
||||
"Ensure you implement all required interfaces correctly, and avoid writing LF/low-level interface implementation classes manually."
|
||||
)
|
||||
object ContractDoesNotImplementRequiringInterface
|
||||
extends ErrorCode(
|
||||
id = "CONTRACT_DOES_NOT_IMPLEMENT_REQUIRING_INTERFACE",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val cause: String,
|
||||
err: LfInterpretationError.ContractDoesNotImplementRequiringInterface,
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
) {
|
||||
|
||||
override def resources: Seq[(ErrorResource, String)] =
|
||||
Seq(
|
||||
(ErrorResource.ContractId, err.coid.coid),
|
||||
(ErrorResource.TemplateId, err.templateId.toString),
|
||||
(ErrorResource.InterfaceId, err.requiredInterfaceId.toString),
|
||||
(ErrorResource.InterfaceId, err.requiringInterfaceId.toString),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error occurs when you attempt to compare two values of different types using the built-in comparison types."""
|
||||
)
|
||||
@Resolution(
|
||||
"Avoid using the low level comparison build, and instead use the Eq class."
|
||||
)
|
||||
object NonComparableValues
|
||||
extends ErrorCode(
|
||||
id = "NON_COMPARABLE_VALUES",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val cause: String
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
) {}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error occurs when a contract key contains a contract ID, which is illegal for hashing reasons."""
|
||||
)
|
||||
@Resolution(
|
||||
"Ensure your contracts key field cannot contain a contract ID."
|
||||
)
|
||||
object ContractIdInContractKey
|
||||
extends ErrorCode(
|
||||
id = "CONTRACT_ID_IN_CONTRACT_KEY",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val cause: String
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
) {}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error occurs when you attempt to compare a global and local contract ID of the same discriminator."""
|
||||
)
|
||||
@Resolution(
|
||||
"Avoid constructing contract IDs manually."
|
||||
)
|
||||
object ContractIdComparability
|
||||
extends ErrorCode(
|
||||
id = "CONTRACT_ID_COMPARABILITY",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val cause: String,
|
||||
err: LfInterpretationError.ContractIdComparability,
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
) {
|
||||
|
||||
override def resources: Seq[(ErrorResource, String)] =
|
||||
Seq(
|
||||
(ErrorResource.ContractId, err.globalCid.coid)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation("This error occurs when you nest values too deeply.")
|
||||
@Resolution("Restructure your code and reduce value nesting.")
|
||||
object ValueNesting
|
||||
extends ErrorCode(id = "VALUE_NESTING", ErrorCategory.InvalidIndependentOfSystemState) {
|
||||
|
||||
final case class Reject(override val cause: String, err: LfInterpretationError.ValueNesting)(
|
||||
implicit loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(cause = cause) {}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.error.definitions.groups
|
||||
|
||||
import com.daml.error.definitions.{ChangeId, LedgerApiErrors}
|
||||
import com.daml.error.{
|
||||
ContextualizedErrorLogger,
|
||||
DamlErrorWithDefiniteAnswer,
|
||||
ErrorCategory,
|
||||
ErrorCode,
|
||||
ErrorGroup,
|
||||
ErrorResource,
|
||||
Explanation,
|
||||
Resolution,
|
||||
}
|
||||
import com.daml.lf.value.Value
|
||||
|
||||
@Explanation(
|
||||
"Potential consistency errors raised due to race conditions during command submission or returned as submission rejections by the backing ledger."
|
||||
)
|
||||
object ConsistencyErrors extends ErrorGroup()(LedgerApiErrors.errorClass) {
|
||||
|
||||
@Explanation("A command with the given command id has already been successfully processed.")
|
||||
@Resolution(
|
||||
"""The correct resolution depends on the use case. If the error received pertains to a submission retried due to a timeout,
|
||||
|do nothing, as the previous command has already been accepted.
|
||||
|If the intent is to submit a new command, re-submit using a distinct command id.
|
||||
|"""
|
||||
)
|
||||
object DuplicateCommand
|
||||
extends ErrorCode(
|
||||
id = "DUPLICATE_COMMAND",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceExists,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val definiteAnswer: Boolean = false,
|
||||
existingCommandSubmissionId: Option[String],
|
||||
changeId: Option[ChangeId] = None,
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = "A command with the given command id has already been successfully processed",
|
||||
definiteAnswer = definiteAnswer,
|
||||
) {
|
||||
override def context: Map[String, String] =
|
||||
super.context ++ existingCommandSubmissionId
|
||||
.map("existing_submission_id" -> _)
|
||||
.toList ++ changeId
|
||||
.map(changeId => Seq("changeId" -> changeId.toString))
|
||||
.getOrElse(Seq.empty)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error occurs if the Daml engine can not find a referenced contract. This
|
||||
|can be caused by either the contract not being known to the participant, or not being known to
|
||||
|the submitting parties or already being archived."""
|
||||
)
|
||||
@Resolution("This error type occurs if there is contention on a contract.")
|
||||
object ContractNotFound
|
||||
extends ErrorCode(
|
||||
id = "CONTRACT_NOT_FOUND",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceMissing,
|
||||
) {
|
||||
|
||||
final case class Reject(
|
||||
override val cause: String,
|
||||
cid: Value.ContractId,
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
(ErrorResource.ContractId, cid.coid)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"An input contract key was re-assigned to a different contract by a concurrent transaction submission."
|
||||
)
|
||||
@Resolution("Retry the transaction submission.")
|
||||
object InconsistentContractKey
|
||||
extends ErrorCode(
|
||||
id = "INCONSISTENT_CONTRACT_KEY",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateOther,
|
||||
) {
|
||||
|
||||
final case class Reject(reason: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(cause = reason)
|
||||
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error signals that within the transaction we got to a point where two contracts with the same key were active."""
|
||||
)
|
||||
@Resolution("This error indicates an application error.")
|
||||
object DuplicateContractKey
|
||||
extends ErrorCode(
|
||||
id = "DUPLICATE_CONTRACT_KEY",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceExists,
|
||||
) {
|
||||
|
||||
final case class Reject(override val cause: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(cause = cause)
|
||||
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"Another command submission with the same change ID (application ID, command ID, actAs) is already being processed."
|
||||
)
|
||||
@Resolution(
|
||||
"""Listen to the command completion stream until a completion for the in-flight command submission is published.
|
||||
|Alternatively, resubmit the command. If the in-flight submission has finished successfully by then,
|
||||
|this will return more detailed information about the earlier one.
|
||||
|If the in-flight submission has failed by then, the resubmission will attempt to record the new transaction on the ledger.
|
||||
|"""
|
||||
)
|
||||
// This command deduplication error is currently used only by Canton.
|
||||
// It is defined here so that the general command deduplication documentation can refer to it.
|
||||
object SubmissionAlreadyInFlight
|
||||
extends ErrorCode(
|
||||
id = "SUBMISSION_ALREADY_IN_FLIGHT",
|
||||
ErrorCategory.ContentionOnSharedResources,
|
||||
)
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.error.definitions.groups
|
||||
|
||||
import com.daml.error.{DamlError, DamlErrorWithDefiniteAnswer, _}
|
||||
|
||||
object IdentityProviderConfigServiceErrorGroup
|
||||
extends AdminServices.IdentityProviderConfigServiceErrorGroup {
|
||||
|
||||
@Explanation(
|
||||
"There was an attempt to update an identity provider config using an invalid update request."
|
||||
)
|
||||
@Resolution(
|
||||
"""|Inspect the error details for specific information on what made the request invalid.
|
||||
|Retry with an adjusted update request."""
|
||||
)
|
||||
object InvalidUpdateIdentityProviderConfigRequest
|
||||
extends ErrorCode(
|
||||
id = "INVALID_IDENTITY_PROVIDER_UPDATE_REQUEST",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
case class Reject(identityProviderId: String, reason: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause =
|
||||
s"Update operation for identity provider config '$identityProviderId' failed due to: $reason"
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
ErrorResource.IdentityProviderConfig -> identityProviderId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation("The identity provider config referred to by the request was not found.")
|
||||
@Resolution(
|
||||
"Check that you are connecting to the right participant node and the identity provider config is spelled correctly, or create the configuration."
|
||||
)
|
||||
object IdentityProviderConfigNotFound
|
||||
extends ErrorCode(
|
||||
id = "IDP_CONFIG_NOT_FOUND",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceMissing,
|
||||
) {
|
||||
case class Reject(operation: String, identityProviderId: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = s"${operation} failed for unknown identity provider id=\"${identityProviderId}\""
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
ErrorResource.IdentityProviderConfig -> identityProviderId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"There already exists an identity provider configuration with the same identity provider id."
|
||||
)
|
||||
@Resolution(
|
||||
"Check that you are connecting to the right participant node and the identity provider id is spelled correctly, or use an identity provider that already exists."
|
||||
)
|
||||
object IdentityProviderConfigAlreadyExists
|
||||
extends ErrorCode(
|
||||
id = "IDP_CONFIG_ALREADY_EXISTS",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceExists,
|
||||
) {
|
||||
case class Reject(operation: String, identityProviderId: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause =
|
||||
s"${operation} failed, as identity provider \"${identityProviderId}\" already exists"
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
ErrorResource.IdentityProviderConfig -> identityProviderId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"There already exists an identity provider configuration with the same issuer."
|
||||
)
|
||||
@Resolution(
|
||||
"Check that you are connecting to the right participant node and the identity provider id is spelled correctly, or use an identity provider that already exists."
|
||||
)
|
||||
object IdentityProviderConfigIssuerAlreadyExists
|
||||
extends ErrorCode(
|
||||
id = "IDP_CONFIG_ISSUER_ALREADY_EXISTS",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceExists,
|
||||
) {
|
||||
case class Reject(operation: String, issuer: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause =
|
||||
s"${operation} failed, as identity provider with issuer \"${issuer}\" already exists"
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
ErrorResource.IdentityProviderConfig -> issuer
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.error.definitions.groups
|
||||
|
||||
import com.daml.error.{
|
||||
ContextualizedErrorLogger,
|
||||
DamlError,
|
||||
DamlErrorWithDefiniteAnswer,
|
||||
ErrorCategory,
|
||||
ErrorCode,
|
||||
ErrorResource,
|
||||
Explanation,
|
||||
Resolution,
|
||||
}
|
||||
|
||||
object PartyManagementServiceErrorGroup extends AdminServices.PartyManagementServiceErrorGroup {
|
||||
|
||||
@Explanation("There was an attempt to update a party using an invalid update request.")
|
||||
@Resolution(
|
||||
"""|Inspect the error details for specific information on what made the request invalid.
|
||||
|Retry with an adjusted update request."""
|
||||
)
|
||||
object InvalidUpdatePartyDetailsRequest
|
||||
extends ErrorCode(
|
||||
id = "INVALID_PARTY_DETAILS_UPDATE_REQUEST",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
case class Reject(party: String, reason: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause = s"Update operation for party '$party' failed due to: $reason"
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
ErrorResource.Party -> party
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""|Concurrent updates to a party can be controlled by supplying an update request with a resource version (this is optional).
|
||||
|A party's resource version can be obtained by reading the party on the Ledger API.
|
||||
|There was attempt to update a party using a stale resource version, indicating that a different process had updated the party earlier."""
|
||||
)
|
||||
@Resolution(
|
||||
"""|Read this party again to obtain its most recent state and
|
||||
|in particular its most recent resource version. Use the obtained information to build and send a new update request."""
|
||||
)
|
||||
object ConcurrentPartyDetailsUpdateDetected
|
||||
extends ErrorCode(
|
||||
id = "CONCURRENT_PARTY_DETAILS_UPDATE_DETECTED",
|
||||
ErrorCategory.ContentionOnSharedResources,
|
||||
) {
|
||||
case class Reject(party: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause =
|
||||
s"Update operation for party '$party' failed due to a concurrent update to the same party"
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
ErrorResource.Party -> party
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation("The party referred to by the request was not found.")
|
||||
@Resolution(
|
||||
"Check that you are connecting to the right participant node and that the party is spelled correctly."
|
||||
)
|
||||
object PartyNotFound
|
||||
extends ErrorCode(
|
||||
id = "PARTY_NOT_FOUND",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceMissing,
|
||||
) {
|
||||
case class Reject(operation: String, party: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = s"Party: '$party' was not found when $operation"
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
ErrorResource.Party -> party
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,280 +0,0 @@
|
||||
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.error.definitions.groups
|
||||
|
||||
import java.time.Duration
|
||||
|
||||
import com.daml.error.definitions.LedgerApiErrors.EarliestOffsetMetadataKey
|
||||
import com.daml.error.definitions.{LedgerApiErrors}
|
||||
import com.daml.error.{
|
||||
ContextualizedErrorLogger,
|
||||
DamlError,
|
||||
DamlErrorWithDefiniteAnswer,
|
||||
ErrorCategory,
|
||||
ErrorCode,
|
||||
ErrorGroup,
|
||||
ErrorResource,
|
||||
Explanation,
|
||||
Resolution,
|
||||
}
|
||||
import com.daml.lf.data.Ref.Identifier
|
||||
|
||||
@Explanation(
|
||||
"Validation errors raised when evaluating requests in the Ledger API."
|
||||
)
|
||||
object RequestValidation extends LedgerApiErrors.RequestValidation {
|
||||
object NotFound extends ErrorGroup() {
|
||||
@Explanation(
|
||||
"This rejection is given when a read request tries to access a package which does not exist on the ledger."
|
||||
)
|
||||
@Resolution("Use a package id pertaining to a package existing on the ledger.")
|
||||
object Package
|
||||
extends ErrorCode(
|
||||
id = "PACKAGE_NOT_FOUND",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceMissing,
|
||||
) {
|
||||
case class Reject(packageId: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = "Could not find package."
|
||||
) {
|
||||
|
||||
override def resources: Seq[(ErrorResource, String)] = {
|
||||
super.resources :+ ((ErrorResource.DalfPackage, packageId))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"The transaction does not exist or the requesting set of parties are not authorized to fetch it."
|
||||
)
|
||||
@Resolution(
|
||||
"Check the transaction id and verify that the requested transaction is visible to the requesting parties."
|
||||
)
|
||||
object Transaction
|
||||
extends ErrorCode(
|
||||
id = "TRANSACTION_NOT_FOUND",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceMissing,
|
||||
) {
|
||||
|
||||
case class Reject(transactionId: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(cause = "Transaction not found, or not visible.") {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
(ErrorResource.TransactionId, transactionId)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"The ledger configuration could not be retrieved. This could happen due to incomplete initialization of the participant or due to an internal system error."
|
||||
)
|
||||
@Resolution("Contact the participant operator.")
|
||||
object LedgerConfiguration
|
||||
extends ErrorCode(
|
||||
id = "LEDGER_CONFIGURATION_NOT_FOUND",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceMissing,
|
||||
) {
|
||||
|
||||
case class Reject()(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = "The ledger configuration could not be retrieved."
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"The queried template or interface ids do not exist."
|
||||
)
|
||||
@Resolution(
|
||||
"Use valid template or interface ids in your query or ask the participant operator to upload the package containing the necessary interfaces/templates."
|
||||
)
|
||||
object TemplateOrInterfaceIdsNotFound
|
||||
extends ErrorCode(
|
||||
id = "TEMPLATES_OR_INTERFACES_NOT_FOUND",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceMissing,
|
||||
) {
|
||||
|
||||
private def buildCause(
|
||||
unknownTemplatesOrInterfaces: Seq[Either[Identifier, Identifier]]
|
||||
): String = {
|
||||
val unknownTemplateIds =
|
||||
unknownTemplatesOrInterfaces.collect { case Left(id) => id.toString }
|
||||
val unknownInterfaceIds =
|
||||
unknownTemplatesOrInterfaces.collect { case Right(id) => id.toString }
|
||||
|
||||
val templatesMessage = if (unknownTemplateIds.nonEmpty) {
|
||||
s"Templates do not exist: [${unknownTemplateIds.mkString(", ")}]. "
|
||||
} else ""
|
||||
val interfacesMessage = if (unknownInterfaceIds.nonEmpty) {
|
||||
s"Interfaces do not exist: [${unknownInterfaceIds.mkString(", ")}]. "
|
||||
} else
|
||||
""
|
||||
(templatesMessage + interfacesMessage).trim
|
||||
}
|
||||
|
||||
case class Reject(unknownTemplatesOrInterfaces: Seq[Either[Identifier, Identifier]])(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(cause = buildCause(unknownTemplatesOrInterfaces)) {
|
||||
override def resources: Seq[(ErrorResource, String)] =
|
||||
unknownTemplatesOrInterfaces.map {
|
||||
case Left(templateId) => ErrorResource.TemplateId -> templateId.toString
|
||||
case Right(interfaceId) => ErrorResource.InterfaceId -> interfaceId.toString
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation("This rejection is given when a read request tries to access pruned data.")
|
||||
@Resolution("Use an offset that is after the pruning offset.")
|
||||
object ParticipantPrunedDataAccessed
|
||||
extends ErrorCode(
|
||||
id = "PARTICIPANT_PRUNED_DATA_ACCESSED",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateOther,
|
||||
) {
|
||||
case class Reject(override val cause: String, earliestOffset: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = cause,
|
||||
extraContext = Map(EarliestOffsetMetadataKey -> earliestOffset),
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"This rejection is given when a read request uses an offset beyond the current ledger end."
|
||||
)
|
||||
@Resolution("Use an offset that is before the ledger end.")
|
||||
object OffsetAfterLedgerEnd
|
||||
extends ErrorCode(
|
||||
id = "OFFSET_AFTER_LEDGER_END",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateSeekAfterEnd,
|
||||
) {
|
||||
case class Reject(offsetType: String, requestedOffset: String, ledgerEnd: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = s"${offsetType} offset (${requestedOffset}) is after ledger end (${ledgerEnd})"
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"This rejection is given when a read request uses an offset invalid in the requests' context."
|
||||
)
|
||||
@Resolution("Inspect the error message and use a valid offset.")
|
||||
object OffsetOutOfRange
|
||||
extends ErrorCode(
|
||||
id = "OFFSET_OUT_OF_RANGE",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateOther,
|
||||
) {
|
||||
case class Reject(message: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(cause = message)
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""Every ledger API command contains a ledger-id which is verified against the running ledger.
|
||||
This error indicates that the provided ledger-id does not match the expected one."""
|
||||
)
|
||||
@Resolution("Ensure that your application is correctly configured to use the correct ledger.")
|
||||
object LedgerIdMismatch
|
||||
extends ErrorCode(
|
||||
id = "LEDGER_ID_MISMATCH",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceMissing,
|
||||
) {
|
||||
case class Reject(expectedLedgerId: String, receivedLegerId: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause =
|
||||
s"Ledger ID '${receivedLegerId}' not found. Actual Ledger ID is '${expectedLedgerId}'.",
|
||||
definiteAnswer = true,
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error is emitted when a mandatory field is not set in a submitted ledger API command."""
|
||||
)
|
||||
@Resolution("Inspect the reason given and correct your application.")
|
||||
object MissingField
|
||||
extends ErrorCode(id = "MISSING_FIELD", ErrorCategory.InvalidIndependentOfSystemState) {
|
||||
case class Reject(missingField: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = s"The submitted command is missing a mandatory field: ${missingField}",
|
||||
extraContext = Map("field_name" -> missingField),
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error is emitted when a submitted ledger API command contains an invalid argument."""
|
||||
)
|
||||
@Resolution("Inspect the reason given and correct your application.")
|
||||
object InvalidArgument
|
||||
extends ErrorCode(id = "INVALID_ARGUMENT", ErrorCategory.InvalidIndependentOfSystemState) {
|
||||
case class Reject(reason: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
// TODO um-for-hub: Update the cause to mention a 'request' instead of a 'command'
|
||||
cause = s"The submitted command has invalid arguments: ${reason}"
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""This error is emitted when a submitted ledger API command contains a field value that cannot be understood."""
|
||||
)
|
||||
@Resolution("Inspect the reason given and correct your application.")
|
||||
object InvalidField
|
||||
extends ErrorCode(id = "INVALID_FIELD", ErrorCategory.InvalidIndependentOfSystemState) {
|
||||
case class Reject(fieldName: String, message: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause =
|
||||
s"The submitted command has a field with invalid value: Invalid field ${fieldName}: ${message}"
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"This error is emitted when a submitted ledger API command specifies an invalid deduplication period."
|
||||
)
|
||||
@Resolution(
|
||||
"Inspect the error message, adjust the value of the deduplication period or ask the participant operator to increase the maximum deduplication period."
|
||||
)
|
||||
object InvalidDeduplicationPeriodField
|
||||
extends ErrorCode(
|
||||
id = "INVALID_DEDUPLICATION_PERIOD",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateOther,
|
||||
) {
|
||||
val ValidMaxDeduplicationFieldKey = "longest_duration"
|
||||
case class Reject(
|
||||
reason: String,
|
||||
maxDeduplicationDuration: Option[Duration],
|
||||
)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = s"The submitted command had an invalid deduplication period: ${reason}"
|
||||
) {
|
||||
override def context: Map[String, String] = {
|
||||
super.context ++ maxDeduplicationDuration
|
||||
.map(ValidMaxDeduplicationFieldKey -> _.toString)
|
||||
.toList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation("""The supplied offset could not be converted to a binary offset.""")
|
||||
@Resolution("Ensure the offset is specified as a hexadecimal string.")
|
||||
object NonHexOffset
|
||||
extends ErrorCode(
|
||||
id = "NON_HEXADECIMAL_OFFSET",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
case class Error(
|
||||
fieldName: String,
|
||||
offsetValue: String,
|
||||
message: String,
|
||||
)(implicit
|
||||
val loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause = s"Offset in ${fieldName} not specified in hexadecimal: ${offsetValue}: ${message}"
|
||||
)
|
||||
}
|
||||
}
|
@ -1,129 +0,0 @@
|
||||
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.error.definitions.groups
|
||||
|
||||
import com.daml.error.{
|
||||
ContextualizedErrorLogger,
|
||||
DamlError,
|
||||
DamlErrorWithDefiniteAnswer,
|
||||
ErrorCategory,
|
||||
ErrorCode,
|
||||
ErrorResource,
|
||||
Explanation,
|
||||
Resolution,
|
||||
}
|
||||
|
||||
object UserManagementServiceErrorGroup extends AdminServices.UserManagementServiceErrorGroup {
|
||||
|
||||
@Explanation("There was an attempt to update a user using an invalid update request.")
|
||||
@Resolution(
|
||||
"""|Inspect the error details for specific information on what made the request invalid.
|
||||
|Retry with an adjusted update request."""
|
||||
)
|
||||
object InvalidUpdateUserRequest
|
||||
extends ErrorCode(
|
||||
id = "INVALID_USER_UPDATE_REQUEST",
|
||||
ErrorCategory.InvalidIndependentOfSystemState,
|
||||
) {
|
||||
case class Reject(userId: String, reason: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause = s"Update operation for user id '$userId' failed due to: $reason"
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
ErrorResource.User -> userId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""|Concurrent updates to a user can be controlled by supplying an update request with a resource version (this is optional).
|
||||
|A user's resource version can be obtained by reading the user on the Ledger API.
|
||||
|There was attempt to update a user using a stale resource version, indicating that a different process had updated the user earlier."""
|
||||
)
|
||||
@Resolution(
|
||||
"""|Read this user again to obtain its most recent state and
|
||||
|in particular its most recent resource version. Use the obtained information to build and send a new update request."""
|
||||
)
|
||||
object ConcurrentUserUpdateDetected
|
||||
extends ErrorCode(
|
||||
id = "CONCURRENT_USER_UPDATE_DETECTED",
|
||||
ErrorCategory.ContentionOnSharedResources,
|
||||
) {
|
||||
case class Reject(userId: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlError(
|
||||
cause =
|
||||
s"Update operation for user '$userId' failed due to a concurrent update to the same user"
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
ErrorResource.User -> userId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation("The user referred to by the request was not found.")
|
||||
@Resolution(
|
||||
"Check that you are connecting to the right participant node and the user-id is spelled correctly, if yes, create the user."
|
||||
)
|
||||
object UserNotFound
|
||||
extends ErrorCode(
|
||||
id = "USER_NOT_FOUND",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceMissing,
|
||||
) {
|
||||
case class Reject(operation: String, userId: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = s"${operation} failed for unknown user \"${userId}\""
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
ErrorResource.User -> userId
|
||||
)
|
||||
}
|
||||
}
|
||||
@Explanation("There already exists a user with the same user-id.")
|
||||
@Resolution(
|
||||
"Check that you are connecting to the right participant node and the user-id is spelled correctly, or use the user that already exists."
|
||||
)
|
||||
object UserAlreadyExists
|
||||
extends ErrorCode(
|
||||
id = "USER_ALREADY_EXISTS",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceExists,
|
||||
) {
|
||||
case class Reject(operation: String, userId: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = s"${operation} failed, as user \"${userId}\" already exists"
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
ErrorResource.User -> userId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"""|A user can have only a limited number of user rights.
|
||||
|There was an attempt to create a user with too many rights or grant too many rights to a user."""
|
||||
)
|
||||
@Resolution(
|
||||
"""|Retry with a smaller number of rights or delete some of the already existing rights of this user.
|
||||
|Contact the participant operator if the limit is too low."""
|
||||
)
|
||||
object TooManyUserRights
|
||||
extends ErrorCode(
|
||||
id = "TOO_MANY_USER_RIGHTS",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateOther,
|
||||
) {
|
||||
case class Reject(operation: String, userId: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(
|
||||
cause = s"${operation} failed, as user \"${userId}\" would have too many rights."
|
||||
) {
|
||||
override def resources: Seq[(ErrorResource, String)] = Seq(
|
||||
ErrorResource.User -> userId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.error.definitions.groups
|
||||
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.error.{
|
||||
ContextualizedErrorLogger,
|
||||
DamlErrorWithDefiniteAnswer,
|
||||
ErrorCategory,
|
||||
ErrorCode,
|
||||
ErrorResource,
|
||||
Explanation,
|
||||
Resolution,
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"Generic submission rejection errors returned by the backing ledger's write service."
|
||||
)
|
||||
object WriteServiceRejections extends LedgerApiErrors.WriteServiceRejections {
|
||||
|
||||
@Explanation("One or more informee parties have not been allocated.")
|
||||
@Resolution(
|
||||
"Check that all the informee party identifiers are correct, allocate all the informee parties, " +
|
||||
"request their allocation or wait for them to be allocated before retrying the transaction submission."
|
||||
)
|
||||
object PartyNotKnownOnLedger
|
||||
extends ErrorCode(
|
||||
id = "PARTY_NOT_KNOWN_ON_LEDGER",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceMissing,
|
||||
) {
|
||||
case class Reject(parties: Set[String])(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(cause = s"Parties not known on ledger: ${parties
|
||||
.mkString("[", ",", "]")}") {
|
||||
override def resources: Seq[(ErrorResource, String)] =
|
||||
parties.map((ErrorResource.Party, _)).toSeq
|
||||
}
|
||||
|
||||
@deprecated(
|
||||
"Corresponds to transaction submission rejections that are not produced anymore.",
|
||||
since = "1.18.0",
|
||||
)
|
||||
case class RejectDeprecated(
|
||||
description: String
|
||||
)(implicit loggingContext: ContextualizedErrorLogger)
|
||||
extends DamlErrorWithDefiniteAnswer(
|
||||
cause = s"Party not known on ledger: $description"
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation("An invalid transaction submission was not detected by the participant.")
|
||||
@Resolution("Contact support.")
|
||||
@deprecated(
|
||||
"Corresponds to transaction submission rejections that are not produced anymore.",
|
||||
since = "1.18.0",
|
||||
)
|
||||
object Disputed
|
||||
extends ErrorCode(
|
||||
id = "DISPUTED",
|
||||
ErrorCategory.SystemInternalAssumptionViolated, // It should have been caught by the participant
|
||||
) {
|
||||
case class Reject(
|
||||
details: String
|
||||
)(implicit loggingContext: ContextualizedErrorLogger)
|
||||
extends DamlErrorWithDefiniteAnswer(
|
||||
cause = s"Disputed: $details"
|
||||
)
|
||||
}
|
||||
|
||||
@Explanation(
|
||||
"The Participant node did not have sufficient resource quota to submit the transaction."
|
||||
)
|
||||
@Resolution(
|
||||
"Inspect the error message and retry after after correcting the underlying issue."
|
||||
)
|
||||
@deprecated(
|
||||
"Corresponds to transaction submission rejections that are not produced anymore.",
|
||||
since = "1.18.0",
|
||||
)
|
||||
object OutOfQuota
|
||||
extends ErrorCode(id = "OUT_OF_QUOTA", ErrorCategory.ContentionOnSharedResources) {
|
||||
case class Reject(reason: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends DamlErrorWithDefiniteAnswer(cause = reason)
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user