<\/span><\/h1>\n\n\n\nIn go, error can wrap another error as well. <\/p>\n\n\n\n
What does wrapping of error mean? It means to create a hierarchy of errors in which a particular instance of error wraps another error and that particular instance itself can be wrapped inside another error. Below is the syntax for wrapping an error<\/p>\n\n\n\n
e := fmt.Errorf(\"... %w ...\", ..., err, ...)<\/code><\/pre>\n\n\n\n%w<\/strong> directive Is used for wrapping the error. The fmt.Errorf <\/strong>should be called with only one %w directive. Let’s see an example.<\/p>\n\n\n\npackage main\n\nimport (\n\t\"fmt\"\n)\n\ntype errorOne struct{}\n\nfunc (e errorOne) Error() string {\n\treturn \"Error One happended\"\n}\n\nfunc main() {\n\n\te1 := errorOne{}\n\n\te2 := fmt.Errorf(\"E2: %w\", e1)\n\n\te3 := fmt.Errorf(\"E3: %w\", e2)\n\n\tfmt.Println(e2)\n\n\tfmt.Println(e3)\n\n}<\/code><\/pre>\n\n\n\nOutput<\/strong><\/p>\n\n\n\nE2: Error One happended\nE3: E2: Error One happended<\/code><\/pre>\n\n\n\nIn the above program, we created a struct errorOne<\/strong> that has an Error<\/strong> method hence it implements the error<\/strong> interface. Then we created an instance of the errorOne<\/strong> struct named e1<\/strong>. Then we wrapped that instance e1<\/strong> into another error e2<\/strong> like this<\/p>\n\n\n\ne2 := fmt.Errorf(\"E2: %w\", e1)<\/code><\/pre>\n\n\n\nThen we wrapped e2<\/strong> into e3<\/strong> like below. <\/p>\n\n\n\ne3 := fmt.Errorf(\"E3: %w\", e2)<\/code><\/pre>\n\n\n\nSo so we created a hierarchy of errors in which e3<\/strong> wraps e2<\/strong> and e2<\/strong> wraps e1<\/strong>. Thus e3<\/strong> also wraps e1<\/strong> transitively. When we print e2 <\/strong> it also prints the error from e1<\/strong> and gives the output.<\/p>\n\n\n\nE2: Error One happended<\/code><\/pre>\n\n\n\nWhen we print e3<\/strong> it prints the error from e2<\/strong> as well as e1<\/strong> and gives the output.<\/p>\n\n\n\nE3: E2: Error One happended<\/code><\/pre>\n\n\n\nNow the question which comes to the mind that whats the use case of wrapping the errors. To understand it let’s see an example<\/p>\n\n\n\n
package main\n\nimport (\n\t\"fmt\"\n)\n\ntype notPositive struct {\n\tnum int\n}\n\nfunc (e notPositive) Error() string {\n\treturn fmt.Sprintf(\"checkPositive: Given number %d is not a positive number\", e.num)\n}\n\ntype notEven struct {\n\tnum int\n}\n\nfunc (e notEven) Error() string {\n\treturn fmt.Sprintf(\"checkEven: Given number %d is not an even number\", e.num)\n}\n\nfunc checkPositive(num int) error {\n\tif num < 0 {\n\t\treturn notPositive{num: num}\n\t}\n\treturn nil\n}\n\nfunc checkEven(num int) error {\n\tif num%2 == 1 {\n\t\treturn notEven{num: num}\n\t}\n\treturn nil\n}\n\nfunc checkPostiveAndEven(num int) error {\n\tif num > 100 {\n\t\treturn fmt.Errorf(\"checkPostiveAndEven: Number %d is greater than 100\", num)\n\t}\n\n\terr := checkPositive(num)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = checkEven(num)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc main() {\n\tnum := 3\n\terr := checkPostiveAndEven(num)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t} else {\n\t\tfmt.Println(\"Givennnumber is positive and even\")\n\t}\n\n}<\/code><\/pre>\n\n\n\nOutput<\/strong><\/p>\n\n\n\ncheckEven: Given number 3 is not an even number<\/code><\/pre>\n\n\n\nIn the above program, we have a function checkPostiveAndEven<\/strong> that checks whether a number is even and positive. In turns, it calls the checkEven<\/strong> function to check if the number is even. And then it calls checkPositive<\/strong> function to check if the number is positive. If a number is not even and positive it an error is raised.<\/p>\n\n\n\nIn the above program it is impossible to tell stack trace of the error. We know that this error came from checkEven<\/strong> function for the above output. But which function called the checkEven<\/strong> function is not clear from the error. This is where wrapping the error comes in the picture. This becomes more useful when the project is big and there are a lot of functions calling each other. Let’s rewrite the program by wrapping the error.<\/p>\n\n\n\npackage main\n\nimport (\n\t\"fmt\"\n)\n\ntype notPositive struct {\n\tnum int\n}\n\nfunc (e notPositive) Error() string {\n\treturn fmt.Sprintf(\"checkPositive: Given number %d is not a positive number\", e.num)\n}\n\ntype notEven struct {\n\tnum int\n}\n\nfunc (e notEven) Error() string {\n\treturn fmt.Sprintf(\"checkEven: Given number %d is not an even number\", e.num)\n}\n\nfunc checkPositive(num int) error {\n\tif num < 0 {\n\t\treturn notPositive{num: num}\n\t}\n\treturn nil\n}\n\nfunc checkEven(num int) error {\n\tif num%2 == 1 {\n\t\treturn notEven{num: num}\n\t}\n\treturn nil\n}\n\nfunc checkPostiveAndEven(num int) error {\n\tif num > 100 {\n\t\treturn fmt.Errorf(\"checkPostiveAndEven: Number %d is greater than 100\", num)\n\t}\n\n\terr := checkPositive(num)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"checkPostiveAndEven: %w\", err)\n\t}\n\n\terr = checkEven(num)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"checkPostiveAndEven: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc main() {\n\tnum := 3\n\terr := checkPostiveAndEven(num)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t} else {\n\t\tfmt.Println(\"Given number is positive and even\")\n\t}\n\n}<\/code><\/pre>\n\n\n\nOutput<\/strong><\/p>\n\n\n\ncheckPostiveAndEven: checkEven: Given number 3 is not an even number<\/code><\/pre>\n\n\n\n The above program is same as the previous program just that in the checkPostiveAndEven<\/strong> function , we wrap the errors like below.<\/p>\n\n\n\nfmt.Errorf(\"checkPostiveAndEven: %w\", err)<\/code><\/pre>\n\n\n\nSo the output is more clear and the error is more informative. The output clearly mentions the sequence of calling as well<\/p>\n\n\n\n
checkPostiveAndEven: checkEven: Given number 3 is not an even number<\/code><\/pre>\n\n\n\n