]>
Commit | Line | Data |
---|---|---|
845f8314 VM |
1 | Error reporting in libgit2 |
2 | ========================== | |
3 | ||
aa94acf0 RB |
4 | Libgit2 tries to follow the POSIX style: functions return an `int` value |
5 | with 0 (zero) indicating success and negative values indicating an error. | |
6 | There are specific negative error codes for each "expected failure" | |
7 | (e.g. `GIT_ENOTFOUND` for files that take a path which might be missing) | |
8 | and a generic error code (-1) for all critical or non-specific failures | |
9 | (e.g. running out of memory or system corruption). | |
10 | ||
11 | When a negative value is returned, an error message is also set. The | |
ac3d33df | 12 | message can be accessed via the `git_error_last` function which will return a |
aa94acf0 RB |
13 | pointer to a `git_error` structure containing the error message text and |
14 | the class of error (i.e. what part of the library generated the error). | |
15 | ||
16 | For instance: An object lookup by SHA prefix (`git_object_lookup_prefix`) | |
17 | has two expected failure cases: the SHA is not found at all which returns | |
18 | `GIT_ENOTFOUND` or the SHA prefix is ambiguous (i.e. two or more objects | |
19 | share the prefix) which returns `GIT_EAMBIGUOUS`. There are any number of | |
20 | critical failures (such as a packfile being corrupted, a loose object | |
21 | having the wrong access permissions, etc.) all of which will return -1. | |
22 | When the object lookup is successful, it will return 0. | |
23 | ||
24 | If libgit2 was compiled with threads enabled (`-DTHREADSAFE=ON` when using | |
25 | CMake), then the error message will be kept in thread-local storage, so it | |
26 | will not be modified by other threads. If threads are not enabled, then | |
27 | the error message is in global data. | |
28 | ||
29 | All of the error return codes, the `git_error` type, the error access | |
30 | functions, and the error classes are defined in `include/git2/errors.h`. | |
31 | See the documentation there for details on the APIs for accessing, | |
32 | clearing, and even setting error codes. | |
33 | ||
34 | When writing libgit2 code, please be smart and conservative when returning | |
35 | error codes. Functions usually have a maximum of two or three "expected | |
36 | errors" and in most cases only one. If you feel there are more possible | |
37 | expected error scenarios, then the API you are writing may be at too high | |
38 | a level for core libgit2. | |
39 | ||
40 | Example usage | |
41 | ------------- | |
42 | ||
43 | When using libgit2, you will typically capture the return value from | |
44 | functions using an `int` variable and check to see if it is negative. | |
45 | When that happens, you can, if you wish, look at the specific value or | |
46 | look at the error message that was generated. | |
845f8314 VM |
47 | |
48 | ~~~c | |
845f8314 | 49 | { |
aa94acf0 RB |
50 | git_repository *repo; |
51 | int error = git_repository_open(&repo, "path/to/repo"); | |
845f8314 | 52 | |
aa94acf0 | 53 | if (error < 0) { |
ac3d33df | 54 | fprintf(stderr, "Could not open repository: %s\n", git_error_last()->message); |
aa94acf0 RB |
55 | exit(1); |
56 | } | |
845f8314 | 57 | |
aa94acf0 | 58 | ... use `repo` here ... |
845f8314 | 59 | |
aa94acf0 | 60 | git_repository_free(repo); /* void function - no error return code */ |
845f8314 VM |
61 | } |
62 | ~~~ | |
63 | ||
aa94acf0 RB |
64 | Some of the error return values do have meaning. Optionally, you can look |
65 | at the specific error values to decide what to do. | |
66 | ||
67 | ~~~c | |
68 | { | |
69 | git_repository *repo; | |
70 | const char *path = "path/to/repo"; | |
71 | int error = git_repository_open(&repo, path); | |
72 | ||
73 | if (error < 0) { | |
74 | if (error == GIT_ENOTFOUND) | |
75 | fprintf(stderr, "Could not find repository at path '%s'\n", path); | |
76 | else | |
77 | fprintf(stderr, "Unable to open repository: %s\n", | |
ac3d33df | 78 | git_error_last()->message); |
aa94acf0 RB |
79 | exit(1); |
80 | } | |
845f8314 | 81 | |
aa94acf0 RB |
82 | ... happy ... |
83 | } | |
84 | ~~~ | |
845f8314 | 85 | |
aa94acf0 RB |
86 | Some of the higher-level language bindings may use a range of information |
87 | from libgit2 to convert error return codes into exceptions, including the | |
88 | specific error return codes and even the class of error and the error | |
ac3d33df | 89 | message returned by `git_error_last`, but the full range of that logic is |
aa94acf0 | 90 | beyond the scope of this document. |
845f8314 | 91 | |
aa94acf0 RB |
92 | Example internal implementation |
93 | ------------------------------- | |
845f8314 | 94 | |
aa94acf0 RB |
95 | Internally, libgit2 detects error scenarios, records error messages, and |
96 | returns error values. Errors from low-level functions are generally | |
97 | passed upwards (unless the higher level can either handle the error or | |
98 | wants to translate the error into something more meaningful). | |
845f8314 | 99 | |
aa94acf0 RB |
100 | ~~~c |
101 | int git_repository_open(git_repository **repository, const char *path) | |
102 | { | |
103 | /* perform some logic to open the repository */ | |
104 | if (p_exists(path) < 0) { | |
ac3d33df | 105 | git_error_set(GIT_ERROR_REPOSITORY, "The path '%s' doesn't exist", path); |
aa94acf0 RB |
106 | return GIT_ENOTFOUND; |
107 | } | |
845f8314 | 108 | |
aa94acf0 RB |
109 | ... |
110 | } | |
111 | ~~~ | |
845f8314 | 112 | |
ac3d33df JK |
113 | Note that some error codes have been defined with a specific meaning in the |
114 | context of callbacks: | |
115 | - `GIT_EUSER` provides a way to bubble up a non libgit2-related failure, which | |
116 | allows it to be preserved all the way up to the initial function call (a `git_cred` | |
117 | setup trying to access an unavailable LDAP server for instance). | |
118 | - `GIT_EPASSTHROUGH` provides a way to tell libgit2 that it should behave as if | |
119 | no callback was provided. This is of special interest to bindings, which would | |
120 | always provide a C function as a "trampoline", and decide at runtime what to do. | |
121 | ||
aa94acf0 RB |
122 | The public error API |
123 | -------------------- | |
845f8314 | 124 | |
ac3d33df | 125 | - `const git_error *git_error_last(void)`: The main function used to look up |
aa94acf0 RB |
126 | the last error. This may return NULL if no error has occurred. |
127 | Otherwise this should return a `git_error` object indicating the class | |
128 | of error and the error message that was generated by the library. | |
ac3d33df JK |
129 | Do not use this function unless the prior call to a libgit2 API |
130 | returned an error, as it can otherwise give misleading results. | |
131 | libgit2's error strings are not cleared aggressively, | |
132 | and this function may return an error string that reflects a prior error, | |
133 | possibly even reflecting internal state. | |
aa94acf0 RB |
134 | |
135 | The last error is stored in thread-local storage when libgit2 is | |
136 | compiled with thread support, so you do not have to worry about another | |
137 | thread overwriting the value. When thread support is off, the last | |
138 | error is a global value. | |
139 | ||
140 | _Note_ There are some known bugs in the library where this may return | |
141 | NULL even when an error code was generated. Please report these as | |
142 | bugs, but in the meantime, please code defensively and check for NULL | |
143 | when calling this function. | |
144 | ||
ac3d33df | 145 | - `void git_error_clear(void)`: This function clears the last error. The |
aa94acf0 RB |
146 | library will call this when an error is generated by low level function |
147 | and the higher level function handles the error. | |
148 | ||
149 | _Note_ There are some known bugs in the library where a low level | |
150 | function's error message is not cleared by higher level code that | |
151 | handles the error and returns zero. Please report these as bugs, but in | |
152 | the meantime, a zero return value from a libgit2 API does not guarantee | |
ac3d33df | 153 | that `git_error_last()` will return NULL. |
aa94acf0 | 154 | |
ac3d33df | 155 | - `void git_error_set(int error_class, const char *message)`: This |
aa94acf0 RB |
156 | function can be used when writing a custom backend module to set the |
157 | libgit2 error message. See the documentation on this function for its | |
158 | use. Normal usage of libgit2 will probably never need to call this API. | |
159 | ||
ac3d33df | 160 | - `void git_error_set_oom(void)`: This is a standard function for reporting |
aa94acf0 RB |
161 | an out-of-memory error. It is written in a manner that it doesn't have |
162 | to allocate any extra memory in order to record the error, so this is | |
163 | the best way to report that scenario. | |
164 | ||
165 | Deviations from the standard | |
166 | ---------------------------- | |
167 | ||
168 | There are some public functions that do not return `int` values. There | |
169 | are two primary cases: | |
170 | ||
171 | * `void` return values: If a function has a `void` return, then it will | |
172 | never fail. This primary will be used for object destructors. | |
173 | ||
174 | * `git_xyz *` return values: These are simple accessor functions where the | |
175 | only meaningful error would typically be looking something up by index | |
176 | and having the index be out of bounds. In those cases, the function | |
177 | will typically return NULL. | |
178 | ||
179 | * Boolean return values: There are some cases where a function cannot fail | |
180 | and wants to return a boolean value. In those cases, we try to return 1 | |
181 | for true and 0 for false. These cases are rare and the return value for | |
182 | the function should probably be an `unsigned int` to denote these cases. | |
183 | If you find an exception, please open an issue and let's fix it. | |
184 | ||
185 | There are a few other exceptions to these rules here and there in the | |
186 | library, but those are extremely rare and should probably be converted | |
187 | over to other to more standard patterns for usage. Feel free to open | |
188 | issues pointing these out. | |
189 | ||
190 | There are some known bugs in the library where some functions may return a | |
191 | negative value but not set an error message and some other functions may | |
192 | return zero (no error) and yet leave an error message set. Please report | |
193 | these cases as issues and they will be fixed. In the meanwhile, please | |
ac3d33df JK |
194 | code defensively, checking that the return value of `git_error_last` is not |
195 | NULL before using it, and not relying on `git_error_last` to return NULL when | |
aa94acf0 RB |
196 | a function returns 0 for success. |
197 | ||
198 | The internal error API | |
199 | ---------------------- | |
845f8314 | 200 | |
ac3d33df | 201 | - `void git_error_set(int error_class, const char *fmt, ...)`: This is the |
aa94acf0 | 202 | main internal function for setting an error. It works like `printf` to |
ac3d33df | 203 | format the error message. See the notes of `git_error_set_str` for a |
aa94acf0 | 204 | general description of how error messages are stored (and also about |
ac3d33df | 205 | special handling for `error_class` of `GIT_ERROR_OS`). |
845f8314 VM |
206 | |
207 | Writing error messages | |
208 | ---------------------- | |
209 | ||
210 | Here are some guidelines when writing error messages: | |
211 | ||
aa94acf0 RB |
212 | - Use proper English, and an impersonal or past tenses: *The given path |
213 | does not exist*, *Failed to lookup object in ODB* | |
845f8314 | 214 | |
aa94acf0 RB |
215 | - Use short, direct and objective messages. **One line, max**. libgit2 is |
216 | a low level library: think that all the messages reported will be thrown | |
217 | as Ruby or Python exceptions. Think how long are common exception | |
218 | messages in those languages. | |
845f8314 | 219 | |
aa94acf0 RB |
220 | - **Do not add redundant information to the error message**, specially |
221 | information that can be inferred from the context. | |
845f8314 | 222 | |
aa94acf0 RB |
223 | E.g. in `git_repository_open`, do not report a message like "Failed to |
224 | open repository: path not found". Somebody is calling that | |
225 | function. If it fails, they already know that the repository failed to | |
226 | open! | |
845f8314 VM |
227 | |
228 | General guidelines for error reporting | |
229 | -------------------------------------- | |
230 | ||
aa94acf0 RB |
231 | - Libgit2 does not handle programming errors with these |
232 | functions. Programming errors are `assert`ed, and when their source is | |
233 | internal, fixed as soon as possible. This is C, people. | |
845f8314 | 234 | |
aa94acf0 RB |
235 | Example of programming errors that would **not** be handled: passing |
236 | NULL to a function that expects a valid pointer; passing a `git_tree` | |
237 | to a function that expects a `git_commit`. All these cases need to be | |
238 | identified with `assert` and fixed asap. | |
845f8314 | 239 | |
aa94acf0 RB |
240 | Example of a runtime error: failing to parse a `git_tree` because it |
241 | contains invalid data. Failing to open a file because it doesn't exist | |
242 | on disk. These errors are handled, a meaningful error message is set, | |
243 | and an error code is returned. | |
845f8314 | 244 | |
aa94acf0 RB |
245 | - In general, *do not* try to overwrite errors internally and *do* |
246 | propagate error codes from lower level functions to the higher level. | |
247 | There are some cases where propagating an error code will be more | |
248 | confusing rather than less, so there are some exceptions to this rule, | |
249 | but the default behavior should be to simply clean up and pass the error | |
250 | on up to the caller. | |
845f8314 | 251 | |
aa94acf0 | 252 | **WRONG** |
845f8314 VM |
253 | |
254 | ~~~c | |
aa94acf0 RB |
255 | int git_commit_parent(...) |
256 | { | |
257 | ... | |
845f8314 | 258 | |
aa94acf0 | 259 | if (git_commit_lookup(parent, repo, parent_id) < 0) { |
ac3d33df | 260 | git_error_set(GIT_ERROR_COMMIT, "Overwrite lookup error message"); |
aa94acf0 RB |
261 | return -1; /* mask error code */ |
262 | } | |
845f8314 | 263 | |
aa94acf0 RB |
264 | ... |
265 | } | |
845f8314 VM |
266 | ~~~ |
267 | ||
aa94acf0 | 268 | **RIGHT** |
845f8314 VM |
269 | |
270 | ~~~c | |
aa94acf0 | 271 | int git_commit_parent(...) |
845f8314 | 272 | { |
aa94acf0 | 273 | ... |
845f8314 | 274 | |
aa94acf0 RB |
275 | error = git_commit_lookup(parent, repo, parent_id); |
276 | if (error < 0) { | |
277 | /* cleanup intermediate objects if necessary */ | |
278 | /* leave error message and propagate error code */ | |
279 | return error; | |
280 | } | |
845f8314 | 281 | |
aa94acf0 RB |
282 | ... |
283 | } | |
284 | ~~~ |