├── .gitignore ├── .vscode └── settings.json ├── FileMaker-Error-Handling.fmp12 ├── Custom Functions ├── CFUpdater.fmp12 ├── ErrorGetType.fmfn ├── ErrorGetCode.fmfn ├── ErrorGetMessage.fmfn ├── ErrorGetAsJSON.fmfn ├── ErrorIfFmpLastError.fmfn ├── ErrorFound.fmfn ├── ErrorIfSetFromJSON.fmfn ├── ErrorGetCustomElement.fmfn ├── ErrorIfScriptResult.fmfn ├── logLevelFromError.fmfn ├── ErrorIfSetCustomElement.fmfn ├── ErrorIfFmp.fmfn ├── ErrorIf.fmfn ├── ErrorIfApp.fmfn ├── README.md ├── Error.Help.fmfn └── ErrorDescriptionFmp.fmfn ├── .editorconfig ├── LICENSE ├── makeFunctionOverview.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | Import.log 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 8, 3 | "editor.rulers": [100, 120] 4 | } 5 | -------------------------------------------------------------------------------- /FileMaker-Error-Handling.fmp12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dansmith65/FileMaker-Error-Handling/HEAD/FileMaker-Error-Handling.fmp12 -------------------------------------------------------------------------------- /Custom Functions/CFUpdater.fmp12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dansmith65/FileMaker-Error-Handling/HEAD/Custom Functions/CFUpdater.fmp12 -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | # Top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = tab 8 | indent_size = 8 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | 14 | [*.md] 15 | # Don't trim trailing whitespace in Markdown (they are used to force line breaks) 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /Custom Functions/ErrorGetType.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * ErrorGetType 4 | * 5 | * PURPOSE: (text) 6 | * Get error type a from private local variable. 7 | * 8 | * RETURNS: 9 | * Text error type, if it exists. 10 | * 11 | * PARAMETERS: none 12 | * 13 | * DEPENDENCIES: 14 | * ErrorGetAsJSON 15 | * 16 | * REFERENCES: 17 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 18 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 19 | * or this sentence shall be included in all copies or substantial portions of the Software. 20 | * 21 | * HISTORY: 22 | * 2024-JUL-08 Daniel Smith dan@filemaker.consulting 23 | * - created with advice from Joshua Willing josh@willingapps.com 24 | * ===================================== 25 | */ 26 | 27 | JSONGetElement ( ErrorGetAsJSON ; "type" ) 28 | -------------------------------------------------------------------------------- /Custom Functions/ErrorGetCode.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * ErrorGetCode 4 | * 5 | * PURPOSE: 6 | * Get error code from a private local variable. 7 | * 8 | * RETURNS: (number or null) 9 | * Numeric error code, if it exists. 10 | * 11 | * PARAMETERS: none 12 | * 13 | * DEPENDENCIES: 14 | * ErrorGetAsJSON 15 | * 16 | * REFERENCES: 17 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 18 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 19 | * or this sentence shall be included in all copies or substantial portions of the Software. 20 | * 21 | * HISTORY: 22 | * 2024-JUL-08 Daniel Smith dan@filemaker.consulting 23 | * - created with advice from Joshua Willing josh@willingapps.com 24 | * ===================================== 25 | */ 26 | 27 | JSONGetElement ( ErrorGetAsJSON ; "code" ) 28 | -------------------------------------------------------------------------------- /Custom Functions/ErrorGetMessage.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * ErrorGetMessage 4 | * 5 | * PURPOSE: (text) 6 | * Get error message a from private local variable. 7 | * 8 | * RETURNS: 9 | * Text error message, if it exists. 10 | * 11 | * PARAMETERS: none 12 | * 13 | * DEPENDENCIES: 14 | * ErrorGetAsJSON 15 | * 16 | * REFERENCES: 17 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 18 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 19 | * or this sentence shall be included in all copies or substantial portions of the Software. 20 | * 21 | * HISTORY: 22 | * 2024-JUL-08 Daniel Smith dan@filemaker.consulting 23 | * - created with advice from Joshua Willing josh@willingapps.com 24 | * ===================================== 25 | */ 26 | 27 | JSONGetElement ( ErrorGetAsJSON ; "message" ) 28 | -------------------------------------------------------------------------------- /Custom Functions/ErrorGetAsJSON.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * ErrorGetAsJSON 4 | * 5 | * PURPOSE: 6 | * Allows for returning an error in a script result or logging it, for example. 7 | * 8 | * RETURNS: (JSON Object) 9 | * Entire error serialized as a JSON object. 10 | * 11 | * PARAMETERS: none 12 | * 13 | * DEPENDENCIES: none 14 | * 15 | * REFERENCES: 16 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 17 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 18 | * or this sentence shall be included in all copies or substantial portions of the Software. 19 | * 20 | * HISTORY: 21 | * 2024-JUL-08 Daniel Smith dan@filemaker.consulting 22 | * - created with advice from Joshua Willing josh@willingapps.com 23 | * ===================================== 24 | */ 25 | 26 | If ( IsEmpty ( $errorPrivate ) ; "{}" ; 27 | $errorPrivate 28 | ) 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 Daniel Smith https://filemaker.consulting 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | associated documentation files (the "Software"), to deal in the Software without restriction, 5 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 6 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 7 | subject to the following conditions: 8 | 9 | Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 10 | or this sentence shall be included in all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 13 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 16 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | -------------------------------------------------------------------------------- /Custom Functions/ErrorIfFmpLastError.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * ErrorIfFmpLastError ( additionalTextInfo ) 4 | * 5 | * PURPOSE: 6 | * Save error information to a private local variable and return a Boolean result. 7 | * Syntactic sugar for the most common way to check for FileMaker errors. 8 | * 9 | * RETURNS: (boolean) 10 | * GetAsBoolean ( Get ( LastError ) ) 11 | * 12 | * PARAMETERS: 13 | * additionalTextInfo = (text, optional) some text describing the particular instance of this error. 14 | * With the addition of Get(LastErrorLocation) in FM 19.6.1, this parameter no longer has 15 | * to help a developer locate where in a script the error occurred. 16 | * 17 | * DEPENDENCIES: 18 | * Custom Functions: ErrorIfFmp 19 | * 20 | * REFERENCES: 21 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 22 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 23 | * or this sentence shall be included in all copies or substantial portions of the Software. 24 | * 25 | * HISTORY: 26 | * 2024-JUL-08 Daniel Smith dan@filemaker.consulting 27 | * - created 28 | * ===================================== 29 | */ 30 | 31 | ErrorIfFmp ( Get ( LastError ) ; additionalTextInfo ) 32 | -------------------------------------------------------------------------------- /Custom Functions/ErrorFound.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * ErrorFound 4 | * 5 | * RETURNS: (boolean) 6 | * True if the private local variable contained an error, otherwise False 7 | * 8 | * DEPENDENCIES: 9 | * ErrorGetAsJSON, ErrorIf, ErrorIfSetCustomElement 10 | * 11 | * REFERENCES: 12 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 13 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 14 | * or this sentence shall be included in all copies or substantial portions of the Software. 15 | * 16 | * HISTORY: 17 | * 2024-JUL-08 Daniel Smith dan@filemaker.consulting 18 | * - created based on various old iterations of the same basic function 19 | * ===================================== 20 | */ 21 | 22 | Case ( 23 | ErrorGetAsJSON = "{}" ; 24 | False 25 | ; 26 | 27 | Left ( ErrorGetAsJSON ; 1 ) ≠ "{" or Right ( ErrorGetAsJSON ; 1 ) ≠ "}" ; 28 | /* DO NOT want to use JSONFormatElements here since this is called by other functions 29 | which get called often so should not alter FileMaker's internal JSON cache unless 30 | an error found. */ 31 | ErrorIf ( True ; "CF: ErrorFound" ; 2 ; "the stored error was not a valid JSON object" ) 32 | and ErrorIfSetCustomElement ( "theErrorObject" ; ErrorGetAsJSON ; JSONString ) 33 | ; 34 | 35 | GetAsBoolean ( 36 | JSONGetElement ( ErrorGetAsJSON ; "code" ) 37 | ) 38 | ) 39 | -------------------------------------------------------------------------------- /Custom Functions/ErrorIfSetFromJSON.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * ErrorIfSetFromJSON ( theErrorObject ) 4 | * 5 | * PURPOSE: 6 | * Allows for loading or clearing an error in these function's internal format from a JSON object. 7 | * Use to evaluate an error returned in a script result, for example. 8 | * 9 | * RETURNS: (boolean) 10 | * Code contained in theErrorData as a Boolean. In other words, if any error 11 | * occurred at all, return True (1), otherwise return False (0). 12 | * 13 | * PARAMETERS: 14 | * theErrorObject = (JSON Object) value returned from ErrorGetAsJSON. It is NOT recommended 15 | * to create an error object manually and pass in to this function. 16 | * 17 | * DEPENDENCIES: 18 | * ErrorFound 19 | * 20 | * REFERENCES: 21 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 22 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 23 | * or this sentence shall be included in all copies or substantial portions of the Software. 24 | * 25 | * HISTORY: 26 | * 2024-JUL-08 Daniel Smith dan@filemaker.consulting 27 | * - created with advice from Joshua Willing josh@willingapps.com 28 | * ===================================== 29 | */ 30 | 31 | If ( ( IsEmpty ( theErrorObject ) or theErrorObject = "{}" ) 32 | and ( IsEmpty ( $errorPrivate ) or $errorPrivate = "{}" ) 33 | ; 34 | False ; 35 | 36 | /* else */ 37 | Let ( $errorPrivate = theErrorObject ; ErrorFound ) 38 | ) 39 | -------------------------------------------------------------------------------- /Custom Functions/ErrorGetCustomElement.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * ErrorGetCustomElement ( keyOrPath ) 4 | * 5 | * PURPOSE: 6 | * Get a value from the custom error object stored in a private local variable. This value 7 | * could be set by many of the Error* custom functions, but is likely to be set by Error, 8 | * ErrorIfFmp, ErrorIfApp, or in user code by the ErrorIfSetCustomElement function. 9 | * 10 | * RETURNS: (any) 11 | * Since the underlying data structure is currently JSON, the return value could be any 12 | * valid JSON type. 13 | * 14 | * PARAMETERS: 15 | * keyOrPath = (text) the key or path to the JSON element to get 16 | * 17 | * NOTE: 18 | * Could validate/transform the keyOrPath like ErrorIfSetCustomElement does, but I've chosen 19 | * not to. ErrorIfSetCustomElement has the potential to delete existing data, so it's more 20 | * important to validate the keyOrPath there. It's also more important to be able to save 21 | * the data than it is to retrieve it with this function so nothing is lost (the assumption 22 | * here is that it will be logged). 23 | * 24 | * DEPENDENCIES: 25 | * ErrorFound, ErrorGetAsJSON 26 | * 27 | * REFERENCES: 28 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 29 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 30 | * or this sentence shall be included in all copies or substantial portions of the Software. 31 | * 32 | * HISTORY: 33 | * 2024-JUL-08 Daniel Smith dan@filemaker.consulting 34 | * - created based on code by Joshua Willing josh@willingapps.com 35 | * ===================================== 36 | */ 37 | 38 | If ( ErrorFound ; 39 | JSONGetElement ( ErrorGetAsJSON ; "custom." & keyOrPath ) 40 | ) 41 | -------------------------------------------------------------------------------- /makeFunctionOverview.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const directory = 'Custom Functions'; 5 | const outputPath = path.join(directory, 'README.md'); 6 | let markdown = '# Custom Function Overview\n\n'; 7 | 8 | fs.readdir(directory, (err, files) => { 9 | if (err) { 10 | console.error(err); 11 | return; 12 | } 13 | 14 | const fmfnFiles = files.filter(file => file.endsWith('.fmfn')); 15 | console.log('fmfnFiles', fmfnFiles); 16 | 17 | // create an index at the top of the file with links to each function overview in the same file 18 | fmfnFiles.forEach(file => { 19 | const filePath = path.join(directory, file); 20 | 21 | const content = fs.readFileSync(filePath, 'utf8'); 22 | const matches = content.match(/===\n\s\*\s([^\n]+)/m); 23 | if (matches) { 24 | const functionPrototype = matches[1]; 25 | let href = file.replace('.', '').toLowerCase(); 26 | markdown += `- [${functionPrototype}](#${href})\n`; 27 | } else { 28 | markdown += `No function prototype found for: ${file}\n`; 29 | } 30 | }); 31 | markdown += `\n`; 32 | 33 | // extract minimal script header from each function file 34 | fmfnFiles.forEach(file => { 35 | const filePath = path.join(directory, file); 36 | markdown += `\n## [${file}](${file})\n\n`; 37 | 38 | const content = fs.readFileSync(filePath, 'utf8'); 39 | const scriptHeaderRegex = /\/\*\*(\*(?!\/)|[^*])*\*\//g; 40 | const matches = content.match(scriptHeaderRegex); 41 | if (matches) { 42 | const scriptHeader = matches[0]; 43 | let minScriptHeader = scriptHeader//.replace(/ \* HISTORY\:.* \* \=/s, ' * ='); 44 | minScriptHeader = minScriptHeader.replace(/ \* REFERENCES\:.* \* =/s, ' * ='); 45 | minScriptHeader = minScriptHeader.replace(/ \* =+\n/g, ''); 46 | markdown += `\`\`\`\n${minScriptHeader}\n\`\`\`\n`; 47 | } 48 | }); 49 | 50 | fs.writeFileSync(outputPath , markdown, err => { 51 | if (err) console.error(err); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /Custom Functions/ErrorIfScriptResult.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * ErrorIfScriptResult ( theScriptName ) 4 | * 5 | * PURPOSE: 6 | * Check for all errors after performing a script that should return JSON with error 7 | * information in a key named "error". 8 | * 9 | * RETURNS: (boolean) 10 | * True for error, otherwise False 11 | * 12 | * PARAMETERS: 13 | * theScriptName = (text, optional) name of the script just performed 14 | * 15 | * DEPENDENCIES: 16 | * Custom Functions: ErrorIfFmpLastError, ErrorIfApp, ErrorIfSetFromJSON, 17 | * ErrorIfSetCustomElement, ErrorGetCustomElement 18 | * 19 | * REFERENCES: 20 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 21 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 22 | * or this sentence shall be included in all copies or substantial portions of the Software. 23 | * 24 | * HISTORY: 25 | * 2024-JUL-08 Daniel Smith dan@filemaker.consulting 26 | * - created based on various old iterations of the same basic function 27 | * ===================================== 28 | */ 29 | 30 | Case ( 31 | ErrorIfFmpLastError ( 32 | "after perform script" 33 | & If ( IsEmpty ( theScriptName ) ; " step" ; 34 | ": " & theScriptName 35 | ) 36 | ) ; 37 | True ; 38 | 39 | /* Confirm that the script result is JSON */ 40 | ErrorIfApp ( Left ( JSONFormatElements ( Get ( ScriptResult ) ) ; 1 ) = "?" ; 41 | 19 ; 42 | theScriptName 43 | ) ; 44 | True ; 45 | 46 | /* Check for an error in the script result */ 47 | ErrorIfSetFromJSON ( JSONGetElement ( Get ( ScriptResult ) ; "error" ) ) ; 48 | ErrorIfSetCustomElement ( "script.stack" ; List ( 49 | Get ( ScriptName ) ; 50 | Let ( ~scriptStack = ErrorGetCustomElement ( "script.stack") ; 51 | If ( IsEmpty ( ~scriptStack ) ; 52 | /* start the stack with the script that generated the error */ 53 | ErrorGetCustomElement ( "script.name" ) ; 54 | /* else: append previous stack */ 55 | ~scriptStack 56 | ) 57 | ) 58 | ) ; JSONString ) ; 59 | 60 | /* Else: No error */ 61 | False 62 | ) 63 | -------------------------------------------------------------------------------- /Custom Functions/logLevelFromError.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * logLevelFromError 4 | * 5 | * PURPOSE: 6 | * Convert an error into the default log level for that error. 7 | * 8 | * RETURNS: 9 | * (number) log level 10 | * 11 | * NOTES: 12 | * It's probably not appropriate to use this function to specify the log level for every 13 | * error, but it is useful for mapping common errors to common log levels. 14 | * 15 | * If logLevel is specified in the error data, then use that. 16 | * 17 | * REFERENCES: 18 | * https://github.com/dansmith65/FileMaker-Error-Handling 19 | * https://github.com/dansmith65/FileMaker-Logger 20 | * 21 | * HISTORY: 22 | * 2024-JUL-22 Daniel Smith dan@filemaker.consulting 23 | * - created based on various old iterations of the same basic function 24 | * - some of those iterations by Joshua Willing josh@willingapps.com 25 | * ===================================== 26 | */ 27 | 28 | Let ( [ 29 | ~errorType = ErrorGetType ; 30 | ~errorCode = ErrorGetCode ; 31 | ~logLevel = ErrorGetCustomElement ( "logLevel" ) 32 | ] ; 33 | Case ( 34 | not IsEmpty ( ~logLevel ) and ~logLevel >= 0 and ~logLevel <= 5 ; 35 | ~logLevel ; 36 | 37 | ~errorCode = 0 ; 38 | 5 ; 39 | 40 | // APP 41 | ~errorType = "App" ; 42 | Case ( 43 | ~errorCode = 1 ; 4 ; // User canceled action 44 | // default 45 | 2 46 | ) ; 47 | 48 | // FMP 49 | ~errorType = "Fmp" ; 50 | Case ( 51 | ~errorCode = 1 ; 4 ; // User canceled action 52 | ~errorCode = 9 ; 2 ; // Insufficient privileges 53 | ~errorCode = 20 ; 4 ; // Command/operation canceled by triggered script 54 | ~errorCode ≥ 200 and ~errorCode <= 213 ; 2 ; // misc. permissions errors 55 | ~errorCode ≥ 215 and ~errorCode <= 218 ; 2 ; // misc. permissions errors 56 | ~errorCode ≥ 300 and ~errorCode <= 304 ; 3 ; // in use by others 57 | ~errorCode = 400 ; 3 ; // Find criteria are empty 58 | ~errorCode = 401 ; 3 ; // No records match the request 59 | ~errorCode ≥ 500 and ~errorCode <= 509 ; 3 ; // validation 60 | ~errorCode = 805 ; 1 ; // File is damaged; use Recover command 61 | ~errorCode ≥ 807 and ~errorCode <= 810 ; 1 ; // file/file system errors 62 | ~errorCode = 812 ; 1 ; // Exceeded host's capacity 63 | ~errorCode = 813 ; 1 ; // Record Synchronization error on network 64 | ~errorCode = 824 ; 1 ; // File is damaged or not a FileMaker file 65 | // default 66 | 2 67 | ) ; 68 | 69 | // ALL OTHER 70 | 2 71 | ) 72 | ) 73 | -------------------------------------------------------------------------------- /Custom Functions/ErrorIfSetCustomElement.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * ErrorIfSetCustomElement ( keyOrPath ; value ; jsonType ) 4 | * 5 | * PURPOSE: 6 | * Set a custom value in the error object stored in a private local variable. 7 | * 8 | * 9 | * RETURNS: (boolean) 10 | * True if an error was stored, which also means it added data to the error. 11 | * False if an error was NOT stored, wich also means it did NOT add data to the error. 12 | * 13 | * PARAMETERS: 14 | * keyOrPath = (text) the key or path to the JSON element to get 15 | * SHOULD NOT start with "_invalidKeys", 16 | * which is a reserved key where values with invalid keys are stored. 17 | * value = the value to set 18 | * jsonType = should be one of the valid types like JSONString 19 | * 20 | * NOTE: 21 | * It is recommended to document values that are commonly set by this function in your 22 | * system. For example, I use these values: 23 | * dialog.title = (string) If set, will override the default custom dialog title. 24 | * dialog.message = (string) If set, will override the default custom dialog message. 25 | * dialog.shown = (boolean) If true, dialog has been shown to the user. 26 | * logLevel = (int) If set, this log level will be used instead of the default. 27 | * 28 | * DEPENDENCIES: 29 | * ErrorFound, ErrorGetAsJSON, ErrorIfSetFromJSON 30 | * 31 | * REFERENCES: 32 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 33 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 34 | * or this sentence shall be included in all copies or substantial portions of the Software. 35 | * 36 | * HISTORY: 37 | * 2024-JUL-08 Daniel Smith dan@filemaker.consulting 38 | * - created based on code by Joshua Willing josh@willingapps.com 39 | * ===================================== 40 | */ 41 | 42 | If ( not ErrorFound ; False ; 43 | Let ( [ 44 | ~keyOrPathIsInvalid = 45 | IsEmpty ( keyOrPath ) 46 | /* Array's are not supported at the root level. */ 47 | or ( 48 | Position ( keyOrPath ; "[" ; 1 ; 1 ) = 1 49 | and 50 | Position ( keyOrPath ; "['" ; 1 ; 1 ) ≠ 1 51 | ) 52 | /* Chose not to support new array syntax, which helps with backwards compatibility 53 | and will hopefully make it easier to transition the underlying data structure, 54 | in case that ever needs to be done. */ 55 | or PatternCount ( keyOrPath ; "[:]" ) 56 | or PatternCount ( keyOrPath ; "[+]" ) 57 | /* Bracket notation could also be more difficult to transition to a new data structure. */ 58 | or PatternCount ( keyOrPath ; "['" ) 59 | ; 60 | ~invalidKeyCount = If ( ~keyOrPathIsInvalid ; 61 | ValueCount ( JSONListKeys ( ErrorGetAsJSON ; "custom._invalidKeys" ) ) 62 | ) ; 63 | ~ = If ( ~keyOrPathIsInvalid ; 64 | /* save keyOrPath in _invalidKeys */ 65 | ErrorIfSetFromJSON ( 66 | JSONSetElement ( ErrorGetAsJSON ; 67 | "custom._invalidKeys[" & ~invalidKeyCount & "]keyOrPath" ; 68 | keyOrPath ; 69 | JSONString 70 | ) 71 | ) 72 | ) ; 73 | ~modifiedKeyOrPath = If ( ~keyOrPathIsInvalid ; 74 | "_invalidKeys[" & ~invalidKeyCount & "]value" ; 75 | keyOrPath 76 | ) 77 | ] ; 78 | ErrorIfSetFromJSON ( 79 | JSONSetElement ( ErrorGetAsJSON ; "custom." & ~modifiedKeyOrPath ; value ; jsonType ) 80 | ) 81 | ) 82 | ) 83 | -------------------------------------------------------------------------------- /Custom Functions/ErrorIfFmp.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * ErrorIfFmp ( theCode ; additionalTextInfo ) 4 | * 5 | * PURPOSE: 6 | * Save error information to a private local variable and return a Boolean result. 7 | * This should only be used for FileMaker-specific error codes. You will most often want 8 | * to use ErrorIfFmpLastError, but this function is necessary when you use EvaluationError, 9 | * which you should be using every time you use Evaluate. 10 | * 11 | * RETURNS: (boolean) 12 | * GetAsBoolean ( theCode ) 13 | * 14 | * PARAMETERS: 15 | * theCode = (number) code for a FileMaker error, which is also used as the condition 16 | * additionalTextInfo = (text, optional) some text describing the particular instance of this error. 17 | * With the addition of Get(LastErrorLocation) in FM 19.6.1, this parameter no longer 18 | * has to help a developer locate where in a script the error occurred. 19 | * 20 | * DEPENDENCIES: 21 | * Custom Functions: ErrorIf, ErrorDescriptionFmp, ErrorIfSetCustomElement 22 | * 23 | * REFERENCES: 24 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 25 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 26 | * or this sentence shall be included in all copies or substantial portions of the Software. 27 | * 28 | * HISTORY: 29 | * 2024-JUL-11 Daniel Smith 30 | * - trim additionalTextInfo, omit trailing period 31 | * 2024-JUL-08 Daniel Smith dan@filemaker.consulting 32 | * - created based on various old iterations of the same basic function 33 | * ===================================== 34 | */ 35 | 36 | If ( not theCode ; ErrorIfSetFromJSON ( "" ) ; Let ( [ 37 | ~additionalText = Trim ( additionalTextInfo ) ; 38 | ~errorMessage = ErrorDescriptionFmp ( theCode ) 39 | & If ( not IsEmpty ( ~additionalText ) ; 40 | ". " & ~additionalText 41 | ) 42 | & If ( not IsEmpty ( Get ( LastErrorDetail ) ) ; 43 | /* I'm not sure if this should always be included or only for certain error codes; 44 | I've seen it return helpful information for 1630 and 1631 codes */ 45 | If ( not IsEmpty ( ~additionalText ) ; ". " ) 46 | & Get ( LastErrorDetail ) 47 | ) 48 | ] ; 49 | ErrorIf ( True ; "Fmp" ; theCode ; ~errorMessage ) 50 | and ErrorIfSetCustomElement ( "lastErrorLocation" ; Get ( LastErrorLocation ) ; JSONString ) 51 | and ErrorIfSetCustomElement ( "lastErrorDetail" ; Get ( LastErrorDetail ) ; JSONString ) 52 | /* add additional info useful for debugging specific errors... */ 53 | and Case ( 54 | theCode = 3 ; 55 | /* Command is unavailable (for example, wrong operating system, wrong mode, etc.) */ 56 | ErrorIfSetCustomElement ( "windowMode" ; Get ( WindowMode ) ; JSONString ) 57 | and ErrorIfSetCustomElement ( "systemPlatform" ; Get ( SystemPlatform ) ; JSONString ) 58 | and ErrorIfSetCustomElement ( "applicationVersion" ; Get ( ApplicationVersion ) ;JSONString ) 59 | and ErrorIfSetCustomElement ( "hostApplicationVersion" ; Get ( HostApplicationVersion ) ; JSONString ) 60 | ; 61 | 62 | theCode = 9 /* Insufficient privileges */ 63 | or Int ( theCode / 100 ) = 2 /* 2xx are permissions related errors*/ 64 | ; 65 | ErrorIfSetCustomElement ( "accountPrivilegeSetName" ; Get ( AccountPrivilegeSetName ) ; JSONString ) 66 | and ErrorIfSetCustomElement ( "currentPrivilegeSetName" ; Get ( CurrentPrivilegeSetName ) ; JSONString ) 67 | ; 68 | /* else: nothing more to add, so return true to not break the logic */ 69 | True 70 | ) 71 | ) ) 72 | -------------------------------------------------------------------------------- /Custom Functions/ErrorIf.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * ErrorIf ( theCondition ; theType ; theCode ; theMessage ) 4 | * 5 | * PURPOSE: 6 | * Save error information to a private local variable, for use by the suite of Error* 7 | * functions. This should be the only function in the suite to create the error, but 8 | * other functions can call it to create an error with a specific type. User code can 9 | * also call this function to create an error with a custom type. 10 | * 11 | * RETURNS: (boolean) 12 | * If GetAsBoolean ( theCondition ), then return GetAsBoolean ( theCode ) 13 | * 14 | * PARAMETERS: 15 | * theCondition = (boolean) Error will only be stored if True. 16 | * theType = (text) origin of the error 17 | * (e.g.: "Fmp", "App", "Plugin: BaseElements", "Module: PluginChecker", "API: QBO", etc.) 18 | * theCode = (number) code for the error 19 | * theMessage = (text) description of the error, preferably human readable, decipherable, 20 | * and in sentence format (ending with a period). 21 | * 22 | * NOTE: 23 | * This function contains a recommended set of environmental data, but you may choose to add 24 | * or remove from this function as you see fit for your solution. All error generating custom 25 | * functions call this function, so it is the central place to define default environmental 26 | * data collected when an error occurs, as long as it applies to all error types. 27 | * 28 | * Environmental data that is likely to change from the time the error occurs to the time log 29 | * data is collected should be included in this function. 30 | * 31 | * DEPENDENCIES: 32 | * Custom Functions: ErrorGetAsJSON, ErrorIfSetFromJSON 33 | * 34 | * REFERENCES: 35 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 36 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 37 | * or this sentence shall be included in all copies or substantial portions of the Software. 38 | * 39 | * HISTORY: 40 | * 2024-JUL-11 Daniel Smith 41 | * - trim theMessage and append a period if it doesn't end with one already 42 | * 2024-JUL-08 Daniel Smith dan@filemaker.consulting 43 | * - created based on various old iterations of the same basic function 44 | * ===================================== 45 | */ 46 | 47 | If ( not theCondition ; ErrorIfSetFromJSON ( "" ) ; 48 | ErrorIfSetFromJSON ( JSONSetElement ( "{}" ; 49 | /** 50 | * Information about the error. 51 | * This code should NOT be modified, these values should be considered "internal" and only 52 | * set by this function and retrieved by specific "getter" functions. 53 | */ 54 | [ "type" ; theType ; JSONString ] ; 55 | [ "code" ; theCode ; JSONNumber ] ; 56 | [ "message" ; 57 | Let ( msg = Trim ( theMessage ) ; 58 | msg & If ( Right ( msg ; 1 ) ≠ "." ; "." ) 59 | ) 60 | ; JSONString ] ; 61 | 62 | /** 63 | * Information about the environment. 64 | * These values should be adjusted as needed for your system and can be accessed by 65 | * case-sensitive name via the ErrorGetCustomElement function. Technically, they should 66 | * also be set by the function named ErrorIfSetCustomElement, so any code below should be 67 | * compatible with those setter/getter functions. 68 | * It's recommended to use lowerCamelCase for custom info, for consistency. 69 | */ 70 | [ "custom.script.name" ; Get ( ScriptName ) ; JSONString ] ; 71 | [ "custom.script.parameter" ; Get ( ScriptParameter ) ; 72 | If ( Left ( JSONFormatElements ( Get ( ScriptParameter ) ) ; 1 ) = "{" ; JSONObject ; JSONString ) 73 | ] ; 74 | [ "custom.script.result" ; Get ( ScriptResult ) ; 75 | If ( Left ( JSONFormatElements ( Get ( ScriptResult ) ) ; 1 ) = "{" ; JSONObject ; JSONString ) 76 | ] ; 77 | [ "custom.script.section" ; $~script.section ; JSONString ] ; 78 | [ "custom.currentTimeUTCMilliseconds" ; Get ( CurrentTimeUTCMilliseconds ) ; JSONNumber ] 79 | ) ) 80 | ) 81 | -------------------------------------------------------------------------------- /Custom Functions/ErrorIfApp.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * ErrorIfApp ( theCondition ; theCode ; additionalTextInfo ) 4 | * 5 | * PURPOSE: 6 | * Save error information to a private local variable and return a Boolean result. 7 | * This should only be used for Application-specific error codes, as defined by YOU! 8 | * Daniel Smith has added the codes he uses, but you should feel free to add or modify 9 | * these codes to suit your needs. Make sure you don't change any codes after you start 10 | * using this function in your application, though! 11 | * 12 | * RETURNS: (boolean) 13 | * GetAsBoolean ( theCondition ) 14 | * 15 | * PARAMETERS: 16 | * theCondition = (boolean) Error will only be stored if True. 17 | * theCode = (number) code for the error 18 | * additionalTextInfo = (text, optional) some text describing the particular instance of this error. 19 | * This should help a developer locate where in a script the error occurred. 20 | * (e.g., "create new invoice record") 21 | * 22 | * DEPENDENCIES: 23 | * Custom Functions: ErrorIf, ErrorIfSetCustomElement 24 | * 25 | * REFERENCES: 26 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 27 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 28 | * or this sentence shall be included in all copies or substantial portions of the Software. 29 | * 30 | * HISTORY: 31 | * 2024-JUL-11 Daniel Smith 32 | * - trim additionalTextInfo, use a period separator instead of semicolon, omit trailing period 33 | * 2024-JUL-08 Daniel Smith dan@filemaker.consulting 34 | * - created based on various old iterations of the same basic function 35 | * - some of those iterations by Joshua Willing josh@willingapps.com 36 | * ===================================== 37 | */ 38 | 39 | If ( not theCondition ; ErrorIfSetFromJSON ( "" ) ; Let ( [ 40 | /* Get human-readable error string associated with the code */ 41 | ~errorDescription = Case ( 42 | theCode = 0 ; "No error" ; 43 | 44 | theCode = 1 ; "User canceled action" ; 45 | 46 | theCode = 2 ; "Invalid parameter" ; 47 | /* Missing or malformed; so if a date is expected but script received a turtle. */ 48 | 49 | theCode = 3 ; "Failed validation" ; 50 | /* Any general-purpose validation that doesn't fit into another more-specific error code. */ 51 | 52 | theCode = 6 ; "Invalid window mode" ; 53 | 54 | theCode = 10 ; "Incompatible FileMaker version" ; 55 | /* Sometimes we offer a feature or two that doesn't run on the lowest supported client version. 56 | In that case, this error could be used to only allow supported clients to run the code. */ 57 | 58 | theCode = 11 ; "Incompatible FileMaker application" ; 59 | /* Might use if FMGo is required for a GPS location based function, but the 60 | feature was run from FMPro. */ 61 | 62 | theCode = 13 ; "Script error" ; 63 | /* I often wonder if I should use this code, or Failed Validation code 3. I think there are 64 | subtle differences, though. Let's say a script set a variable to the value of "a", "b" or "c", 65 | then later tested which value it was. I would throw this code in an `Else` since the same 66 | script set the variable, so there is just some internal error that isn't because of a 67 | parameter. It might be able to be called validation error, but the script itself is what was 68 | invalid, so I use this code.*/ 69 | 70 | theCode = 16 ; "Plug-In error" ; 71 | /* Use when a plugin doesn't have a specific error handling function 72 | (which set's the type to the plugin name) */ 73 | 74 | theCode = 17 ; "ExecuteSQL error" ; 75 | 76 | theCode = 19 ; "Invalid script result" ; 77 | /* Set by ErrorIfScriptResult function. It's like code 2, but for script results. 78 | You could also use it when translating a module's result and that process fails. */ 79 | 80 | theCode = 20 ; "Pardon our dust; this feature is not yet available" ; 81 | 82 | "Unknown error code" 83 | ) ; 84 | ~errorMessage = ~errorDescription 85 | & If ( not IsEmpty ( Trim ( additionalTextInfo ) ) ; 86 | ". " & Trim ( additionalTextInfo ) 87 | ) 88 | ] ; 89 | ErrorIf ( True ; "App" ; theCode ; ~errorMessage ) 90 | /* add additional info useful for debugging specific errors... */ 91 | & Case ( 92 | theCode = 6 ; 93 | ErrorIfSetCustomElement ( "windowMode" ; Get ( WindowMode ) ; JSONString ) ; 94 | 95 | theCode = 10 or theCode = 11 ; 96 | ErrorIfSetCustomElement ( "applicationVersion" ; Get ( ApplicationVersion ) ; JSONString ) ; 97 | 98 | theCode = 18 ; 99 | ErrorIfSetCustomElement ( "foundCount" ; Get ( FoundCount ) ; JSONString ) 100 | ) 101 | ) ) 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | This is a set of custom functions used for error handling in Claris FileMaker. They are NOT compatible with any prior release and should only be used for new projects, or those worth the effort to replace existing functions with. They are intended to be the only means of accessing error data. In other words: you don't have to keep track of an `$error` variable yourself (when comparing these to older versions in this repo, for example). They _currently_ use a local variable under-the-hood, so the error information is only available within the current scope (script) and you must pass the error to any calling scripts yourself. Don't worry; the sample file included in this repository has examples of how to do that and use these functions in various situations. 4 | 5 | 6 | 7 | ## Short Summary of Functions 8 | 9 | All `ErrorIf*` functions will save error data to a local variable and return `True` if the error code is Truthy. 10 | 11 | `ErrorFound` returns `True` if an error was saved with an `ErrorIf*` function. 12 | 13 | `ErrorGet*` functions will retrieve info from a saved error. 14 | 15 | `ErrorIfSetCustomElement` will save additional info with the error and return `True` if an error had already been saved or `False` if it wasn't. This allows you to call it in the same expression as an `ErrorIf*` function. For example: 16 | 17 | ``` 18 | ErrorIfFmpLastError ( "Insert from URL" ) 19 | and ErrorIfSetCustomElement ( "url" ; $url ; JSONString ) 20 | ``` 21 | 22 | For further reading, the [Custom Function Overview](./Custom%20Functions/README.md) lists all the functions and their documentation. 23 | 24 | Better yet, open the [FileMaker-Error-Handling.fmp12](FileMaker-Error-Handling.fmp12) file for real-world(ish) examples of how I use these functions. As an added bonus, I integrated with an API in a way that I consider a best practice for doing so. If you want to, or have ever integrated with an API; you might want to review the scripts in this file just for that reason. 25 | 26 | 27 | 28 | ## FAQ 29 | 30 | > Why should I care about the "type" of an error? 31 | 32 | Every error was generated by some code. The type tells you who owns that code. If you can imagine a world without error types (difficult, I know!) then error code 401 means [No records match the request](https://help.claris.com/en/pro-help/content/error-codes.html#:~:text=No%20records%20match%20the%20request), right? Well, HTTP status codes would disagree and call that [Unauthorized](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401), so who's right? Both! as long as you save the type of error, so you can make sense of the error code. 33 | 34 | 35 | > But I only see "Fmp" and "App" error types; what if a plugin, API, or custom funciton generates an error? 36 | 37 | Make up a type and use it as needed; I do it all the time! The [ErrorFound](./Custom%20Functions/ErrorFound.fmfn) function uses a type of `CF: ErrorFound` if the error data is invalid. I often use the [BaseElements](https://baseelementsplugin.com) plugin and if I use it more than a few times in a project I usually add an `ErrorIfPluginBaseElements` custom function specifically to handle it's errors. 38 | 39 | 40 | > What do you mean, they _currently_ use a local variable under-the-hood? 41 | 42 | These functions intentionally abstract the storage method for the error information. They are meant to be used like an API (Application Programming Interface); a way for two or more computer programs or components to communicate with each other. So while you do have access to it's internal storage mechanisim it is highly recommended NOT to do so. Following this recommendation gives you the advantage of being able to support either future or past internal storage mechanisms without changing any code that calls these functions. 43 | 44 | Note that I did not use a global variable because it's not clear to me how best to clear it. An `ErrorIf*` function could _always_ clear it, but that leaves the last error always hanging out in that global variable so if some other script checked if an error was found before it set/cleared an error, that could cause issues. It also doesn't work in a multi-file solution, so there _has_ to be a fall-back of passing an error to a calling script via a script result and I chose to only implement that method. 45 | 46 | 47 | > What's with "the" in parameter names? 48 | 49 | It's to prevent naming collisions that might prevent you from easily installing these functions; or others after you install these. It's been a long time since I experienced this issue or tested it, but I have had some functions fail to paste because the function name matched the parameter name of an existing custom function (or vice-versa, maybe?). 50 | 51 | 52 | > I'm already using ___ error functions; how do I switch to these? 53 | 54 | Honestly, you probably shouldn't. All past error functions in this repository are 100% valid in a current/modern solution. Those published by others are also likely to be equaly valid, but I can't can't really comment on the unknown. If you _really_ want to switch and have determined that the cost to do so is is justafiable, I'd recommend renaming all existing error handling functions (prepend them with `z_deprecated_`, for example) before adding these functions to your solution. 55 | -------------------------------------------------------------------------------- /Custom Functions/README.md: -------------------------------------------------------------------------------- 1 | # Custom Function Overview 2 | 3 | - [Error.Help ( emptyOrTopic )](#errorhelp.fmfn) 4 | - [ErrorDescriptionFmp ( theCode )](#errordescriptionfmpfmfn) 5 | - [ErrorFound](#errorfoundfmfn) 6 | - [ErrorGetAsJSON](#errorgetasjsonfmfn) 7 | - [ErrorGetCode](#errorgetcodefmfn) 8 | - [ErrorGetCustomElement ( keyOrPath )](#errorgetcustomelementfmfn) 9 | - [ErrorGetMessage](#errorgetmessagefmfn) 10 | - [ErrorGetType](#errorgettypefmfn) 11 | - [ErrorIf ( theCondition ; theType ; theCode ; theMessage )](#erroriffmfn) 12 | - [ErrorIfApp ( theCondition ; theCode ; additionalTextInfo )](#errorifappfmfn) 13 | - [ErrorIfFmp ( theCode ; additionalTextInfo )](#erroriffmpfmfn) 14 | - [ErrorIfFmpLastError ( additionalTextInfo )](#erroriffmplasterrorfmfn) 15 | - [ErrorIfScriptResult ( theScriptName )](#errorifscriptresultfmfn) 16 | - [ErrorIfSetCustomElement ( keyOrPath ; value ; jsonType )](#errorifsetcustomelementfmfn) 17 | - [ErrorIfSetFromJSON ( theErrorObject )](#errorifsetfromjsonfmfn) 18 | 19 | 20 | ## [Error.Help.fmfn](Error.Help.fmfn) 21 | 22 | ``` 23 | /** 24 | * Error.Help ( emptyOrTopic ) 25 | * 26 | * PURPOSE: 27 | * Provide in-app help for this suite of custom functions. 28 | * Meant to be called from the data viewer. 29 | * 30 | * RETURNS: (text) 31 | * 32 | * PARAMETERS: 33 | * emptyOrTopic = (text) the topic to get help with; see code below for valid values 34 | * 35 | */ 36 | ``` 37 | 38 | ## [ErrorDescriptionFmp.fmfn](ErrorDescriptionFmp.fmfn) 39 | 40 | ``` 41 | /** 42 | * ErrorDescriptionFmp ( theCode ) 43 | * 44 | * RETURNS: (text) 45 | * FileMaker's description associated with an error code. 46 | * 47 | * PARAMETERS: 48 | * theCode = (number) code for a FileMaker error 49 | * 50 | * DEPENDENCIES: none 51 | * 52 | */ 53 | ``` 54 | 55 | ## [ErrorFound.fmfn](ErrorFound.fmfn) 56 | 57 | ``` 58 | /** 59 | * ErrorFound 60 | * 61 | * RETURNS: (boolean) 62 | * True if the private local variable contained an error, otherwise False 63 | * 64 | * DEPENDENCIES: 65 | * ErrorGetAsJSON, ErrorIf, ErrorIfSetCustomElement 66 | * 67 | */ 68 | ``` 69 | 70 | ## [ErrorGetAsJSON.fmfn](ErrorGetAsJSON.fmfn) 71 | 72 | ``` 73 | /** 74 | * ErrorGetAsJSON 75 | * 76 | * PURPOSE: 77 | * Allows for returning an error in a script result or logging it, for example. 78 | * 79 | * RETURNS: (JSON Object) 80 | * Entire error serialized as a JSON object. 81 | * 82 | * PARAMETERS: none 83 | * 84 | * DEPENDENCIES: none 85 | * 86 | */ 87 | ``` 88 | 89 | ## [ErrorGetCode.fmfn](ErrorGetCode.fmfn) 90 | 91 | ``` 92 | /** 93 | * ErrorGetCode 94 | * 95 | * PURPOSE: 96 | * Get error code from a private local variable. 97 | * 98 | * RETURNS: (number or null) 99 | * Numeric error code, if it exists. 100 | * 101 | * PARAMETERS: none 102 | * 103 | * DEPENDENCIES: 104 | * ErrorGetAsJSON 105 | * 106 | */ 107 | ``` 108 | 109 | ## [ErrorGetCustomElement.fmfn](ErrorGetCustomElement.fmfn) 110 | 111 | ``` 112 | /** 113 | * ErrorGetCustomElement ( keyOrPath ) 114 | * 115 | * PURPOSE: 116 | * Get a value from the custom error object stored in a private local variable. This value 117 | * could be set by many of the Error* custom functions, but is likely to be set by Error, 118 | * ErrorIfFmp, ErrorIfApp, or in user code by the ErrorIfSetCustomElement function. 119 | * 120 | * RETURNS: (any) 121 | * Since the underlying data structure is currently JSON, the return value could be any 122 | * valid JSON type. 123 | * 124 | * PARAMETERS: 125 | * keyOrPath = (text) the key or path to the JSON element to get 126 | * 127 | * NOTE: 128 | * Could validate/transform the keyOrPath like ErrorIfSetCustomElement does, but I've chosen 129 | * not to. ErrorIfSetCustomElement has the potential to delete existing data, so it's more 130 | * important to validate the keyOrPath there. It's also more important to be able to save 131 | * the data than it is to retrieve it with this function so nothing is lost (the assumption 132 | * here is that it will be logged). 133 | * 134 | * DEPENDENCIES: 135 | * ErrorFound, ErrorGetAsJSON 136 | * 137 | */ 138 | ``` 139 | 140 | ## [ErrorGetMessage.fmfn](ErrorGetMessage.fmfn) 141 | 142 | ``` 143 | /** 144 | * ErrorGetMessage 145 | * 146 | * PURPOSE: (text) 147 | * Get error message a from private local variable. 148 | * 149 | * RETURNS: 150 | * Text error message, if it exists. 151 | * 152 | * PARAMETERS: none 153 | * 154 | * DEPENDENCIES: 155 | * ErrorGetAsJSON 156 | * 157 | */ 158 | ``` 159 | 160 | ## [ErrorGetType.fmfn](ErrorGetType.fmfn) 161 | 162 | ``` 163 | /** 164 | * ErrorGetType 165 | * 166 | * PURPOSE: (text) 167 | * Get error type a from private local variable. 168 | * 169 | * RETURNS: 170 | * Text error type, if it exists. 171 | * 172 | * PARAMETERS: none 173 | * 174 | * DEPENDENCIES: 175 | * ErrorGetAsJSON 176 | * 177 | */ 178 | ``` 179 | 180 | ## [ErrorIf.fmfn](ErrorIf.fmfn) 181 | 182 | ``` 183 | /** 184 | * ErrorIf ( theCondition ; theType ; theCode ; theMessage ) 185 | * 186 | * PURPOSE: 187 | * Save error information to a private local variable, for use by the suite of Error* 188 | * functions. This should be the only function in the suite to create the error, but 189 | * other functions can call it to create an error with a specific type. User code can 190 | * also call this function to create an error with a custom type. 191 | * 192 | * RETURNS: (boolean) 193 | * If GetAsBoolean ( theCondition ), then return GetAsBoolean ( theCode ) 194 | * 195 | * PARAMETERS: 196 | * theCondition = (boolean) Error will only be stored if True. 197 | * theType = (text) origin of the error 198 | * (e.g.: "Fmp", "App", "Plugin: BaseElements", "Module: PluginChecker", "API: QBO", etc.) 199 | * theCode = (number) code for the error 200 | * theMessage = (text) description of the error, preferably human readable, decipherable, 201 | * and in sentence format (ending with a period). 202 | * 203 | * NOTE: 204 | * This function contains a recommended set of environmental data, but you may choose to add 205 | * or remove from this function as you see fit for your solution. All error generating custom 206 | * functions call this function, so it is the central place to define default environmental 207 | * data collected when an error occurs, as long as it applies to all error types. 208 | * 209 | * Environmental data that is likely to change from the time the error occurs to the time log 210 | * data is collected should be included in this function. 211 | * 212 | * DEPENDENCIES: 213 | * Custom Functions: ErrorGetAsJSON, ErrorIfSetFromJSON 214 | * 215 | */ 216 | ``` 217 | 218 | ## [ErrorIfApp.fmfn](ErrorIfApp.fmfn) 219 | 220 | ``` 221 | /** 222 | * ErrorIfApp ( theCondition ; theCode ; additionalTextInfo ) 223 | * 224 | * PURPOSE: 225 | * Save error information to a private local variable and return a Boolean result. 226 | * This should only be used for Application-specific error codes, as defined by YOU! 227 | * Daniel Smith has added the codes he uses, but you should feel free to add or modify 228 | * these codes to suit your needs. Make sure you don't change any codes after you start 229 | * using this function in your application, though! 230 | * 231 | * RETURNS: (boolean) 232 | * GetAsBoolean ( theCondition ) 233 | * 234 | * PARAMETERS: 235 | * theCondition = (boolean) Error will only be stored if True. 236 | * theCode = (number) code for the error 237 | * additionalTextInfo = (text, optional) some text describing the particular instance of this error. 238 | * This should help a developer locate where in a script the error occurred. 239 | * (e.g., "create new invoice record") 240 | * 241 | * DEPENDENCIES: 242 | * Custom Functions: ErrorIf, ErrorIfSetCustomElement 243 | * 244 | */ 245 | ``` 246 | 247 | ## [ErrorIfFmp.fmfn](ErrorIfFmp.fmfn) 248 | 249 | ``` 250 | /** 251 | * ErrorIfFmp ( theCode ; additionalTextInfo ) 252 | * 253 | * PURPOSE: 254 | * Save error information to a private local variable and return a Boolean result. 255 | * This should only be used for FileMaker-specific error codes. You will most often want 256 | * to use ErrorIfFmpLastError, but this function is necessary when you use EvaluationError, 257 | * which you should be using every time you use Evaluate. 258 | * 259 | * RETURNS: (boolean) 260 | * GetAsBoolean ( theCode ) 261 | * 262 | * PARAMETERS: 263 | * theCode = (number) code for a FileMaker error, which is also used as the condition 264 | * additionalTextInfo = (text, optional) some text describing the particular instance of this error. 265 | * With the addition of Get(LastErrorLocation) in FM 19.6.1, this parameter no longer 266 | * has to help a developer locate where in a script the error occurred. 267 | * 268 | * DEPENDENCIES: 269 | * Custom Functions: ErrorIf, ErrorDescriptionFmp, ErrorIfSetCustomElement 270 | * 271 | */ 272 | ``` 273 | 274 | ## [ErrorIfFmpLastError.fmfn](ErrorIfFmpLastError.fmfn) 275 | 276 | ``` 277 | /** 278 | * ErrorIfFmpLastError ( additionalTextInfo ) 279 | * 280 | * PURPOSE: 281 | * Save error information to a private local variable and return a Boolean result. 282 | * Syntactic sugar for the most common way to check for FileMaker errors. 283 | * 284 | * RETURNS: (boolean) 285 | * GetAsBoolean ( Get ( LastError ) ) 286 | * 287 | * PARAMETERS: 288 | * additionalTextInfo = (text, optional) some text describing the particular instance of this error. 289 | * With the addition of Get(LastErrorLocation) in FM 19.6.1, this parameter no longer has 290 | * to help a developer locate where in a script the error occurred. 291 | * 292 | * DEPENDENCIES: 293 | * Custom Functions: ErrorIfFmp 294 | * 295 | */ 296 | ``` 297 | 298 | ## [ErrorIfScriptResult.fmfn](ErrorIfScriptResult.fmfn) 299 | 300 | ``` 301 | /** 302 | * ErrorIfScriptResult ( theScriptName ) 303 | * 304 | * PURPOSE: 305 | * Check for all errors after performing a script that should return JSON with error 306 | * information in a key named "error". 307 | * 308 | * RETURNS: (boolean) 309 | * True for error, otherwise False 310 | * 311 | * PARAMETERS: 312 | * theScriptName = (text, optional) name of the script just performed 313 | * 314 | * DEPENDENCIES: 315 | * Custom Functions: ErrorIfFmpLastError, ErrorIfApp, ErrorIfSetFromJSON, 316 | * ErrorIfSetCustomElement, ErrorGetCustomElement 317 | * 318 | */ 319 | ``` 320 | 321 | ## [ErrorIfSetCustomElement.fmfn](ErrorIfSetCustomElement.fmfn) 322 | 323 | ``` 324 | /** 325 | * ErrorIfSetCustomElement ( keyOrPath ; value ; jsonType ) 326 | * 327 | * PURPOSE: 328 | * Set a custom value in the error object stored in a private local variable. 329 | * 330 | * 331 | * RETURNS: (boolean) 332 | * True if an error was stored, which also means it added data to the error. 333 | * False if an error was NOT stored, wich also means it did NOT add data to the error. 334 | * 335 | * PARAMETERS: 336 | * keyOrPath = (text) the key or path to the JSON element to get 337 | * SHOULD NOT start with "_invalidKeys", 338 | * which is a reserved key where values with invalid keys are stored. 339 | * value = the value to set 340 | * jsonType = should be one of the valid types like JSONString 341 | * 342 | * NOTE: 343 | * It is recommended to document values that are commonly set by this function in your 344 | * system. For example, I use these values: 345 | * dialog.title = (string) If set, will override the default custom dialog title. 346 | * dialog.message = (string) If set, will override the default custom dialog message. 347 | * dialog.shown = (boolean) If true, dialog has been shown to the user. 348 | * logLevel = (int) If set, this log level will be used instead of the default. 349 | * 350 | * DEPENDENCIES: 351 | * ErrorFound, ErrorGetAsJSON, ErrorIfSetFromJSON 352 | * 353 | */ 354 | ``` 355 | 356 | ## [ErrorIfSetFromJSON.fmfn](ErrorIfSetFromJSON.fmfn) 357 | 358 | ``` 359 | /** 360 | * ErrorIfSetFromJSON ( theErrorObject ) 361 | * 362 | * PURPOSE: 363 | * Allows for loading or clearing an error in these function's internal format from a JSON object. 364 | * Use to evaluate an error returned in a script result, for example. 365 | * 366 | * RETURNS: (boolean) 367 | * Code contained in theErrorData as a Boolean. In other words, if any error 368 | * occurred at all, return True (1), otherwise return False (0). 369 | * 370 | * PARAMETERS: 371 | * theErrorObject = (JSON Object) value returned from ErrorGetAsJSON. It is NOT recommended 372 | * to create an error object manually and pass in to this function. 373 | * 374 | * DEPENDENCIES: 375 | * ErrorFound 376 | * 377 | */ 378 | ``` 379 | -------------------------------------------------------------------------------- /Custom Functions/Error.Help.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * Error.Help ( emptyOrTopic ) 4 | * 5 | * PURPOSE: 6 | * Provide in-app help for this suite of custom functions. 7 | * Meant to be called from the data viewer. 8 | * 9 | * RETURNS: (text) 10 | * 11 | * PARAMETERS: 12 | * emptyOrTopic = (text) the topic to get help with; see code below for valid values 13 | * 14 | * REFERENCES: 15 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 16 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 17 | * or this sentence shall be included in all copies or substantial portions of the Software. 18 | * 19 | * NOTE: 20 | * This function is named differently than other functions so it sorts at the top of this group of functions. 21 | * 22 | * HISTORY: 23 | * 2024-JUL-08 Daniel Smith dan@filemaker.consulting 24 | * - created with advice from Cristos Lianides-Chin and Jody Barney 25 | * ===================================== 26 | */ 27 | 28 | Let ( [ 29 | shortSummary = /* "Short Summary" section of main README: */ 30 | "## Short Summary of Functions¶¶All `ErrorIf*` functions will save error data to a local variable and return `True` if the error code is Truthy.¶¶`ErrorFound` returns `True` if an error was saved with an `ErrorIf*` function.¶¶`ErrorGet*` functions will retrieve info from a saved error.¶¶`ErrorIfSetCustomElement` will save additional info with the error and return `True` if an error had already been saved or `False` if it wasn't. This allows you to call it in the same expression as an `ErrorIf*` function. For example:¶¶```¶ErrorIfFmpLastError ( \"Insert from URL\" )¶and ErrorIfSetCustomElement ( \"url\" ; $url ; JSONString )¶```¶¶For further reading, the [Custom Function Overview](./Custom%20Functions/README.md) lists all the functions and their documentation.¶¶Better yet, open the [FileMaker-Error-Handling.fmp12](FileMaker-Error-Handling.fmp12) file for real-world(ish) examples of how I use these functions. As an added bonus, I integrated with an API in a way that I consider a best practice for doing so. If you want to, or have ever integrated with an API; you might want to review the scripts in this file just for that reason." 31 | ; 32 | app = /* App codes, messages, and explanation of when to use them, followed by the date they were updated */ 33 | "theCode = 0 ; \"No error\" ;¶¶theCode = 1 ; \"User canceled action\" ;¶¶theCode = 2 ; \"Invalid parameter\" ;¶ /* Missing or malformed; so if a date is expected but script received a turtle. */¶¶theCode = 3 ; \"Failed validation\" ;¶ /* Any general-purpose validation that doesn't fit into another more-specific error code. */¶¶theCode = 6 ; \"Invalid window mode\" ;¶¶theCode = 10 ; \"Incompatible FileMaker version\" ;¶ /* Sometimes we offer a feature or two that doesn't run on the lowest supported client version.¶ In that case, this error could be used to only allow supported clients to run the code. */¶¶theCode = 11 ; \"Incompatible FileMaker application\" ;¶ /* Might use if FMGo is required for a GPS location based function, but the¶ feature was run from FMPro. */¶¶theCode = 13 ; \"Script error\" ;¶ /* I often wonder if I should use this code, or Failed Validation code 3. I think there are¶ subtle differences, though. Let's say a script set a variable to the value of \"a\", \"b\" or \"c\",¶ then later tested which value it was. I would throw this code in an `Else` since the same¶ script set the variable, so there is just some internal error that isn't because of a¶ parameter. It might be able to be called validation error, but the script itself is what was¶ invalid, so I use this code.*/¶¶theCode = 16 ; \"Plug-In error\" ;¶ /* Use when a plugin doesn't have a specific error handling function¶ (which set's the type to the plugin name) */¶¶theCode = 17 ; \"ExecuteSQL error\" ;¶¶theCode = 19 ; \"Invalid script result\" ;¶ /* Set by ErrorIfScriptResult function. It's like code 2, but for script results.¶ You could also use it when translating a module's result and that process fails. */¶¶theCode = 20 ; \"Pardon our dust. This feature is not yet available.\" ;¶¶¶(current as of 2024-JUL-08)" 34 | ; 35 | functions = /* Entire readme from Custom Functions folder */ 36 | "# Custom Function Overview¶¶- [Error.Help ( emptyOrTopic )](#errorhelp.fmfn)¶- [ErrorDescriptionFmp ( theCode )](#errordescriptionfmpfmfn)¶- [ErrorFound](#errorfoundfmfn)¶- [ErrorGetAsJSON](#errorgetasjsonfmfn)¶- [ErrorGetCode](#errorgetcodefmfn)¶- [ErrorGetCustomElement ( keyOrPath )](#errorgetcustomelementfmfn)¶- [ErrorGetMessage](#errorgetmessagefmfn)¶- [ErrorGetType](#errorgettypefmfn)¶- [ErrorIf ( theCondition ; theType ; theCode ; theMessage )](#erroriffmfn)¶- [ErrorIfApp ( theCondition ; theCode ; additionalTextInfo )](#errorifappfmfn)¶- [ErrorIfFmp ( theCode ; additionalTextInfo )](#erroriffmpfmfn)¶- [ErrorIfFmpLastError ( additionalTextInfo )](#erroriffmplasterrorfmfn)¶- [ErrorIfScriptResult ( theScriptName )](#errorifscriptresultfmfn)¶- [ErrorIfSetCustomElement ( keyOrPath ; value ; jsonType )](#errorifsetcustomelementfmfn)¶- [ErrorIfSetFromJSON ( theErrorObject )](#errorifsetfromjsonfmfn)¶¶¶## [Error.Help.fmfn](Error.Help.fmfn)¶¶```¶/**¶ * Error.Help ( emptyOrTopic )¶ *¶ * PURPOSE:¶ * Provide in-app help for this suite of custom functions.¶ * Meant to be called from the data viewer.¶ *¶ * RETURNS: (text)¶ *¶ * PARAMETERS:¶ * emptyOrTopic = (text) the topic to get help with; see code below for valid values¶ *¶ */¶```¶¶## [ErrorDescriptionFmp.fmfn](ErrorDescriptionFmp.fmfn)¶¶```¶/**¶ * ErrorDescriptionFmp ( theCode )¶ *¶ * RETURNS: (text)¶ * FileMaker's description associated with an error code.¶ *¶ * PARAMETERS:¶ * theCode = (number) code for a FileMaker error¶ *¶ * DEPENDENCIES: none¶ *¶ */¶```¶¶## [ErrorFound.fmfn](ErrorFound.fmfn)¶¶```¶/**¶ * ErrorFound¶ *¶ * RETURNS: (boolean)¶ * True if the private local variable contained an error, otherwise False¶ *¶ * DEPENDENCIES:¶ * ErrorGetAsJSON, ErrorIf, ErrorIfSetCustomElement¶ *¶ */¶```¶¶## [ErrorGetAsJSON.fmfn](ErrorGetAsJSON.fmfn)¶¶```¶/**¶ * ErrorGetAsJSON¶ *¶ * PURPOSE:¶ * Allows for returning an error in a script result or logging it, for example.¶ *¶ * RETURNS: (JSON Object)¶ * Entire error serialized as a JSON object.¶ *¶ * PARAMETERS: none¶ *¶ * DEPENDENCIES: none¶ *¶ */¶```¶¶## [ErrorGetCode.fmfn](ErrorGetCode.fmfn)¶¶```¶/**¶ * ErrorGetCode¶ *¶ * PURPOSE:¶ * Get error code from a private local variable.¶ *¶ * RETURNS: (number or null)¶ * Numeric error code, if it exists.¶ *¶ * PARAMETERS: none¶ *¶ * DEPENDENCIES:¶ * ErrorGetAsJSON¶ *¶ */¶```¶¶## [ErrorGetCustomElement.fmfn](ErrorGetCustomElement.fmfn)¶¶```¶/**¶ * ErrorGetCustomElement ( keyOrPath )¶ *¶ * PURPOSE:¶ * Get a value from the custom error object stored in a private local variable. This value¶ * could be set by many of the Error* custom functions, but is likely to be set by Error,¶ * ErrorIfFmp, ErrorIfApp, or in user code by the ErrorIfSetCustomElement function.¶ *¶ * RETURNS: (any)¶ * Since the underlying data structure is currently JSON, the return value could be any¶ * valid JSON type.¶ *¶ * PARAMETERS:¶ * keyOrPath = (text) the key or path to the JSON element to get¶ *¶ * NOTE:¶ * Could validate/transform the keyOrPath like ErrorIfSetCustomElement does, but I've chosen¶ * not to. ErrorIfSetCustomElement has the potential to delete existing data, so it's more¶ * important to validate the keyOrPath there. It's also more important to be able to save¶ * the data than it is to retrieve it with this function so nothing is lost (the assumption¶ * here is that it will be logged).¶ *¶ * DEPENDENCIES:¶ * ErrorFound, ErrorGetAsJSON¶ *¶ */¶```¶¶## [ErrorGetMessage.fmfn](ErrorGetMessage.fmfn)¶¶```¶/**¶ * ErrorGetMessage¶ *¶ * PURPOSE: (text)¶ * Get error message a from private local variable.¶ *¶ * RETURNS:¶ * Text error message, if it exists.¶ *¶ * PARAMETERS: none¶ *¶ * DEPENDENCIES:¶ * ErrorGetAsJSON¶ *¶ */¶```¶¶## [ErrorGetType.fmfn](ErrorGetType.fmfn)¶¶```¶/**¶ * ErrorGetType¶ *¶ * PURPOSE: (text)¶ * Get error type a from private local variable.¶ *¶ * RETURNS:¶ * Text error type, if it exists.¶ *¶ * PARAMETERS: none¶ *¶ * DEPENDENCIES:¶ * ErrorGetAsJSON¶ *¶ */¶```¶¶## [ErrorIf.fmfn](ErrorIf.fmfn)¶¶```¶/**¶ * ErrorIf ( theCondition ; theType ; theCode ; theMessage )¶ *¶ * PURPOSE:¶ * Save error information to a private local variable, for use by the suite of Error*¶ * functions. This should be the only function in the suite to create the error, but¶ * other functions can call it to create an error with a specific type. User code can¶ * also call this function to create an error with a custom type.¶ *¶ * RETURNS: (boolean)¶ * If GetAsBoolean ( theCondition ), then return GetAsBoolean ( theCode )¶ *¶ * PARAMETERS:¶ * theCondition = (boolean) Error will only be stored if True.¶ * theType = (text) origin of the error¶ * (e.g.: \"Fmp\", \"App\", \"Plugin: BaseElements\", \"Module: PluginChecker\", \"API: QBO\", etc.)¶ * theCode = (number) code for the error¶ * theMessage = (text) description of the error, preferably human readable, decipherable,¶ * and in sentence format (ending with a period).¶ *¶ * NOTE:¶ * This function contains a recommended set of environmental data, but you may choose to add¶ * or remove from this function as you see fit for your solution. All error generating custom¶ * functions call this function, so it is the central place to define default environmental¶ * data collected when an error occurs, as long as it applies to all error types.¶ *¶ * Environmental data that is likely to change from the time the error occurs to the time log¶ * data is collected should be included in this function.¶ *¶ * DEPENDENCIES:¶ * Custom Functions: ErrorGetAsJSON, ErrorIfSetFromJSON¶ *¶ */¶```¶¶## [ErrorIfApp.fmfn](ErrorIfApp.fmfn)¶¶```¶/**¶ * ErrorIfApp ( theCondition ; theCode ; additionalTextInfo )¶ *¶ * PURPOSE:¶ * Save error information to a private local variable and return a Boolean result.¶ * This should only be used for Application-specific error codes, as defined by YOU!¶ * Daniel Smith has added the codes he uses, but you should feel free to add or modify¶ * these codes to suit your needs. Make sure you don't change any codes after you start¶ * using this function in your application, though!¶ *¶ * RETURNS: (boolean)¶ * GetAsBoolean ( theCondition )¶ *¶ * PARAMETERS:¶ * theCondition = (boolean) Error will only be stored if True.¶ * theCode = (number) code for the error¶ * additionalTextInfo = (text, optional) some text describing the particular instance of this error.¶ * This should help a developer locate where in a script the error occurred.¶ * (e.g., \"create new invoice record\")¶ *¶ * DEPENDENCIES:¶ * Custom Functions: ErrorIf, ErrorIfSetCustomElement¶ *¶ */¶```¶¶## [ErrorIfFmp.fmfn](ErrorIfFmp.fmfn)¶¶```¶/**¶ * ErrorIfFmp ( theCode ; additionalTextInfo )¶ *¶ * PURPOSE:¶ * Save error information to a private local variable and return a Boolean result.¶ * This should only be used for FileMaker-specific error codes. You will most often want¶ * to use ErrorIfFmpLastError, but this function is necessary when you use EvaluationError,¶ * which you should be using every time you use Evaluate.¶ *¶ * RETURNS: (boolean)¶ * GetAsBoolean ( theCode )¶ *¶ * PARAMETERS:¶ * theCode = (number) code for a FileMaker error, which is also used as the condition¶ * additionalTextInfo = (text, optional) some text describing the particular instance of this error.¶ * With the addition of Get(LastErrorLocation) in FM 19.6.1, this parameter no longer¶ * has to help a developer locate where in a script the error occurred.¶ *¶ * DEPENDENCIES:¶ * Custom Functions: ErrorIf, ErrorDescriptionFmp, ErrorIfSetCustomElement¶ *¶ */¶```¶¶## [ErrorIfFmpLastError.fmfn](ErrorIfFmpLastError.fmfn)¶¶```¶/**¶ * ErrorIfFmpLastError ( additionalTextInfo )¶ *¶ * PURPOSE:¶ * Save error information to a private local variable and return a Boolean result.¶ * Syntactic sugar for the most common way to check for FileMaker errors.¶ *¶ * RETURNS: (boolean)¶ * GetAsBoolean ( Get ( LastError ) )¶ *¶ * PARAMETERS:¶ * additionalTextInfo = (text, optional) some text describing the particular instance of this error.¶ * With the addition of Get(LastErrorLocation) in FM 19.6.1, this parameter no longer has¶ * to help a developer locate where in a script the error occurred.¶ *¶ * DEPENDENCIES:¶ * Custom Functions: ErrorIfFmp¶ *¶ */¶```¶¶## [ErrorIfScriptResult.fmfn](ErrorIfScriptResult.fmfn)¶¶```¶/**¶ * ErrorIfScriptResult ( theScriptName )¶ *¶ * PURPOSE:¶ * Check for all errors after performing a script that should return JSON with error¶ * information in a key named \"error\".¶ *¶ * RETURNS: (boolean)¶ * True for error, otherwise False¶ *¶ * PARAMETERS:¶ * theScriptName = (text, optional) name of the script just performed¶ *¶ * DEPENDENCIES:¶ * Custom Functions: ErrorIfFmpLastError, ErrorIfApp, ErrorIfSetFromJSON,¶ * ErrorIfSetCustomElement, ErrorGetCustomElement¶ *¶ */¶```¶¶## [ErrorIfSetCustomElement.fmfn](ErrorIfSetCustomElement.fmfn)¶¶```¶/**¶ * ErrorIfSetCustomElement ( keyOrPath ; value ; jsonType )¶ *¶ * PURPOSE:¶ * Set a custom value in the error object stored in a private local variable.¶ *¶ *¶ * RETURNS: (boolean)¶ * True if an error was stored, which also means it added data to the error.¶ * False if an error was NOT stored, wich also means it did NOT add data to the error.¶ *¶ * PARAMETERS:¶ * keyOrPath = (text) the key or path to the JSON element to get¶ * SHOULD NOT start with \"_invalidKeys\",¶ * which is a reserved key where values with invalid keys are stored.¶ * value = the value to set¶ * jsonType = should be one of the valid types like JSONString¶ *¶ * NOTE:¶ * It is recommended to document values that are commonly set by this function in your¶ * system. For example, I use these values:¶ * dialog.title = (string) If set, will override the default custom dialog title.¶ * dialog.message = (string) If set, will override the default custom dialog message.¶ * dialog.shown = (boolean) If true, dialog has been shown to the user.¶ * logLevel = (int) If set, this log level will be used instead of the default.¶ *¶ * DEPENDENCIES:¶ * ErrorFound, ErrorGetAsJSON, ErrorIfSetFromJSON¶ *¶ */¶```¶¶## [ErrorIfSetFromJSON.fmfn](ErrorIfSetFromJSON.fmfn)¶¶```¶/**¶ * ErrorIfSetFromJSON ( theErrorObject )¶ *¶ * PURPOSE:¶ * Allows for loading or clearing an error in these function's internal format from a JSON object.¶ * Use to evaluate an error returned in a script result, for example.¶ *¶ * RETURNS: (boolean)¶ * Code contained in theErrorData as a Boolean. In other words, if any error¶ * occurred at all, return True (1), otherwise return False (0).¶ *¶ * PARAMETERS:¶ * theErrorObject = (JSON Object) value returned from ErrorGetAsJSON. It is NOT recommended¶ * to create an error object manually and pass in to this function.¶ *¶ * DEPENDENCIES:¶ * ErrorFound¶ *¶ */¶```¶" 37 | ; 38 | type = /* FAQ about types, with links removed (copy the rendered markdown) */ 39 | "Why should I care about the \"type\" of an error?¶¶Every error was generated by some code. The type tells you who owns that code. If you can imagine a world without error types (difficult, I know!) then error code 401 means No records match the request, right? Well, HTTP status codes would disagree and call that Unauthorized, so who's right? Both! as long as you save the type of error, so you can make sense of the error code." 40 | ; 41 | url = "https://github.com/dansmith65/FileMaker-Error-Handling" 42 | ] ; 43 | Case ( 44 | emptyOrTopic = "app" ; app ; 45 | emptyOrTopic = "functions" ; functions ; 46 | emptyOrTopic = "type" ; type ; 47 | emptyOrTopic = "url" ; url ; 48 | 49 | /* else: default/general help */ 50 | If ( emptyOrTopic ≠ "" ; 51 | "Invalid parameter, showing general help instead...¶¶" 52 | ) 53 | & "Minimal in-app help for this suite of custom functions¶" 54 | & "------------------------------------------------------" 55 | & "¶¶Valid values for the parameter to this help function are:" 56 | & "¶ app: list of app errors" 57 | & "¶ functions: minimal script header from all functions" 58 | & "¶ type: FAQ about types" 59 | & "¶ url: link to full documentation" 60 | & "¶¶Full documentation can be found at:¶ " & url 61 | & "¶¶¶" & shortSummary 62 | ) 63 | ) 64 | -------------------------------------------------------------------------------- /Custom Functions/ErrorDescriptionFmp.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * ErrorDescriptionFmp ( theCode ) 4 | * 5 | * RETURNS: (text) 6 | * FileMaker's description associated with an error code. 7 | * 8 | * PARAMETERS: 9 | * theCode = (number) code for a FileMaker error 10 | * 11 | * DEPENDENCIES: none 12 | * 13 | * REFERENCES: 14 | * Full documentation can be found at https://github.com/dansmith65/FileMaker-Error-Handling. 15 | * Either [the entire license](https://github.com/dansmith65/FileMaker-Error-Handling/blob/master/LICENSE) 16 | * or this sentence shall be included in all copies or substantial portions of the Software. 17 | * https://help.claris.com/en/pro-help/content/error-codes.html 18 | * https://help.claris.com/archive/fm20/en/pro-help/content/error-codes.html 19 | * https://help.claris.com/archive/fm19/en/pro-help/content/error-codes.html 20 | * https://fmhelp.filemaker.com/help/18/fmp/en/#page/FMP_Help%2Ferror-codes.html 21 | * https://fmhelp.filemaker.com/help/17/fmp/en/#page/FMP_Help%2Ferror-codes.html 22 | * https://fmhelp.filemaker.com/help/16/fmp/en/#page/FMP_Help%2Ferror-codes.html 23 | * https://fmhelp.filemaker.com/help/15/fmp/en/#page/FMP_Help%2Ferror-codes.html 24 | * https://fmhelp.filemaker.com/help/14/fmp/en/html/error_codes.html#1030072 25 | * https://fmhelp.filemaker.com/help/13/fmp/en/html/error_codes.html#1030072 26 | * https://fmhelp.filemaker.com/help/12/fmp/en/html/error_codes.html#1030072 27 | * 28 | * HISTORY: 29 | * MODIFIED on 2024-JUL-08 by Daniel Smith 30 | * - modify message for codes 718 and 719 based on application version 31 | * thanks to input from Beverly Voth 32 | * MODIFIED on 2024-JUN-13 by Josh Willing josh@willingapps.com 33 | * - add error codes from FM21 34 | * MODIFIED on 2024-APR-12 by Daniel Smith 35 | * - add error codes from FM20 36 | * MODIFIED on 2020-AUG-21 by Daniel Smith dan@filemaker.consulting 37 | * - add error codes from FM18 and FM19 38 | * - remove " (*)" from description and add comment: "WPE or REST API" 39 | * MODIFIED on 2019-JUN-01 by Daniel Smith dan@filemaker.consulting 40 | * - rename from ErrorFmpDescription to ErrorDescriptionFmp 41 | * MODIFIED on 2019-MAY-30 by Daniel Smith dan@filemaker.consulting 42 | * - modified ErrorFmp function to only return a text description 43 | * MODIFIED on 2019-FEB-08 by Daniel Smith dan@filemaker.consulting 44 | * - added LastExternalErrorDetail for error code 301 45 | * - remove ~errorCode Let variable; directly use theCode 46 | * MODIFIED on 2019-FEB-08 by Daniel Smith dan@filemaker.consulting 47 | * - update for FM17 error codes 48 | * - used creative merging of differences in descriptions. My goal was 49 | * useful error messages for as many FM versions as possible. 50 | * - added comments specifying when a code was added/removed 51 | * - change error type from "Fmp" to "FMP" 52 | * MODIFIED on 2017-JUL-26 by Daniel Smith dan@filemaker.consulting 53 | * - update for FM16 error codes 54 | * - also include codes deleted since FM11 was released 55 | * MODIFIED on 2013-NOV-22 by Daniel Smith dansmith65@gmail.com 56 | * - rename to ErrorFmp, update documentation 57 | * CREATED on 2019-MAY-30 Daniel Smith dansmith65@gmail.com 58 | * ===================================== 59 | */ 60 | 61 | Let ( theCode = GetAsNumber ( theCode ) ; Case ( 62 | theCode < 100 ; 63 | Case ( 64 | theCode = -1 ; "Unknown error" ; 65 | theCode = 0 ; "No error" ; 66 | theCode = 1 ; "User canceled action" ; 67 | theCode = 2 ; "Memory error" ; 68 | theCode = 3 ; "Command is unavailable (for example, wrong operating system or mode)" ; 69 | theCode = 4 ; "Command is unknown" ; 70 | theCode = 5 ; "Command is invalid (for example, a Set Field script step does not have a calculation specified)" ; 71 | theCode = 6 ; "File is read-only" ; 72 | theCode = 7 ; "Running out of memory" ; 73 | theCode = 8 ; "Empty result" ; /* removed in FM20 */ 74 | theCode = 9 ; "Insufficient privileges" ; 75 | theCode = 10 ; "Requested data is missing" ; 76 | theCode = 11 ; "Name is not valid" ; 77 | theCode = 12 ; "Name already exists" ; 78 | theCode = 13 ; "File or object is in use" ; 79 | theCode = 14 ; "Out of range" ; 80 | theCode = 15 ; "Can't divide by zero" ; 81 | theCode = 16 ; "Operation failed; request retry (for example, a user query)" ; 82 | theCode = 17 ; "Attempt to convert foreign character set to UTF-16 failed" ; 83 | theCode = 18 ; "Client must provide account information to proceed" ; 84 | theCode = 19 ; "String contains characters other than A-Z, a-z, 0-9 (ASCII)" ; 85 | theCode = 20 ; "Command/operation canceled by triggered script" ; 86 | theCode = 21 ; "Request not supported (for example, when creating a hard link on a file system that does not support hard links)" ; /* added in FM13 */ 87 | "Unknown error code" 88 | ) ; 89 | 90 | theCode < 200 ; 91 | Case ( 92 | theCode = 100 ; "File is missing" ; 93 | theCode = 101 ; "Record is missing" ; 94 | theCode = 102 ; "Field is missing" ; 95 | theCode = 103 ; "Relationship is missing" ; 96 | theCode = 104 ; "Script is missing" ; 97 | theCode = 105 ; "Layout is missing" ; 98 | theCode = 106 ; "Table is missing" ; 99 | theCode = 107 ; "Index is missing" ; 100 | theCode = 108 ; "Value list is missing" ; 101 | theCode = 109 ; "Privilege set is missing" ; 102 | theCode = 110 ; "Related tables are missing" ; 103 | theCode = 111 ; "Field repetition is invalid" ; 104 | theCode = 112 ; "Window is missing" ; 105 | theCode = 113 ; "Function is missing" ; 106 | theCode = 114 ; "File reference is missing" ; 107 | theCode = 115 ; "Menu set is missing" ; 108 | theCode = 116 ; "Layout object is missing" ; 109 | theCode = 117 ; "Data source is missing" ; 110 | theCode = 118 ; "Theme is missing" ; /* added in FM12 */ 111 | theCode = 130 ; "Files are damaged or missing and must be reinstalled" ; 112 | theCode = 131 ; "Language pack files are missing" ; 113 | "Unknown error code" 114 | ) ; 115 | 116 | theCode < 300 ; 117 | Case ( 118 | theCode = 200 ; "Record access is denied" ; 119 | theCode = 201 ; "Field cannot be modified" ; 120 | theCode = 202 ; "Field access is denied" ; 121 | theCode = 203 ; "No records in file to print, or password doesn't allow print access" ; 122 | theCode = 204 ; "No access to field(s) in sort order" ; 123 | theCode = 205 ; "User does not have access privileges to create new records; import will overwrite existing data" ; 124 | theCode = 206 ; "User does not have password change privileges, or file is not modifiable" ; 125 | theCode = 207 ; "User does not have privileges to change database schema, or file is not modifiable" ; 126 | theCode = 208 ; "Password does not contain enough characters" ; 127 | theCode = 209 ; "New password must be different from existing one" ; 128 | theCode = 210 ; "User account is inactive" ; 129 | theCode = 211 ; "Password has expired" ; 130 | theCode = 212 ; "Invalid user account or password" ; 131 | theCode = 213 ; "User account and/or password does not exist" ; /* removed in FM17 */ 132 | theCode = 214 ; "Too many login attempts" ; 133 | theCode = 215 ; "Administrator privileges cannot be duplicated" ; 134 | theCode = 216 ; "Guest account cannot be duplicated" ; 135 | theCode = 217 ; "User does not have sufficient privileges to modify administrator account" ; 136 | theCode = 218 ; "Password and verify password do not match" ; /* added in FM12 */ 137 | theCode = 219 ; "Cannot open file; must be licensed user; contact team manager" ; /* added in FM18 */ 138 | "Unknown error code" 139 | ) ; 140 | 141 | theCode < 500 ; 142 | Case ( 143 | theCode = 300 ; "File is locked or in use" ; 144 | theCode = 301 ; "Record is in use by another user" ; 145 | theCode = 302 ; "Table is in use by another user" ; 146 | theCode = 303 ; "Database schema is in use by another user" ; 147 | theCode = 304 ; "Layout is in use by another user" ; 148 | theCode = 306 ; "Record modification ID does not match" ; 149 | theCode = 307 ; "Transaction could not be locked because of a communication error with the host" ; /* added in FM12 */ 150 | theCode = 308 ; "Theme is locked and in use by another user" ; /* added in FM12 */ 151 | theCode = 400 ; "Find criteria are empty" ; 152 | theCode = 401 ; "No records match the request" ; 153 | theCode = 402 ; "Selected field is not a match field for a lookup" ; 154 | theCode = 403 ; "Exceeding maximum record limit for trial version of FileMaker Pro" ; /* removed in FM17 */ 155 | theCode = 404 ; "Sort order is invalid" ; 156 | theCode = 405 ; "Number of records specified exceeds number of records that can be omitted" ; 157 | theCode = 406 ; "Replace/reserialize criteria are invalid" ; 158 | theCode = 407 ; "One or both match fields are missing (invalid relationship)" ; 159 | theCode = 408 ; "Specified field has inappropriate data type for this operation" ; 160 | theCode = 409 ; "Import order is invalid" ; 161 | theCode = 410 ; "Export order is invalid" ; 162 | theCode = 412 ; "Wrong version of FileMaker Pro used to recover file" ; 163 | theCode = 413 ; "Specified field has inappropriate field type" ; 164 | theCode = 414 ; "Layout cannot display the result" ; 165 | theCode = 415 ; "One or more required related records are not available" ; 166 | theCode = 416 ; "A primary key is required from the data source table" ; 167 | theCode = 417 ; "File is not a supported data source" ; 168 | theCode = 418 ; "Internal failure in INSERT operation into a field" ; /* added in FM13 */ 169 | "Unknown error code" 170 | ) ; 171 | 172 | theCode < 700 ; 173 | Case ( 174 | theCode = 500 ; "Date value does not meet validation entry options" ; 175 | theCode = 501 ; "Time value does not meet validation entry options" ; 176 | theCode = 502 ; "Number value does not meet validation entry options" ; 177 | theCode = 503 ; "Value in field is not within the range specified in validation entry options" ; 178 | theCode = 504 ; "Value in field is not unique, as required in validation entry options" ; 179 | theCode = 505 ; "Value in field is not an existing value in the file, as required in validation entry options" ; 180 | theCode = 506 ; "Value in field is not listed in the value list specified in validation entry option" ; 181 | theCode = 507 ; "Value in field failed calculation test of validation entry option" ; 182 | theCode = 508 ; "Invalid value entered in Find mode" ; 183 | theCode = 509 ; "Field requires a valid value" ; 184 | theCode = 510 ; "Related value is empty or unavailable" ; 185 | theCode = 511 ; "Value in field exceeds maximum field size" ; 186 | theCode = 512 ; "Record was already modified by another user" ; 187 | theCode = 513 ; "No validation was specified but data cannot fit into the field" ; /* added in FM13 */ 188 | theCode = 600 ; "Print error has occurred" ; 189 | theCode = 601 ; "Combined header and footer exceed one page" ; 190 | theCode = 602 ; "Body doesn't fit on a page for current column setup" ; 191 | theCode = 603 ; "Print connection lost" ; 192 | "Unknown error code" 193 | ) ; 194 | 195 | theCode < 800 ; 196 | Case ( 197 | theCode = 700 ; "File is of the wrong file type for import" ; 198 | theCode = 706 ; "EPS file has no preview image" ; 199 | theCode = 707 ; "Graphic translator cannot be found" ; 200 | theCode = 708 ; "Can't import the file, or need color monitor support to import file" ; 201 | theCode = 709 ; "QuickTime movie import failed" ; /* removed in FM14 */ 202 | theCode = 710 ; "Unable to update QuickTime reference because the database file is read-only" ; /* removed in FM14 */ 203 | theCode = 711 ; "Import translator cannot be found" ; 204 | theCode = 714 ; "Password privileges do not allow the operation" ; 205 | theCode = 715 ; "Specified Excel worksheet or named range is missing" ; 206 | theCode = 716 ; "A SQL query using DELETE, INSERT, or UPDATE is not allowed for ODBC import" ; 207 | theCode = 717 ; "There is not enough XML/XSL information to proceed with the import or export" ; 208 | theCode = 718 ; If ( GetAsNumber ( Get ( ApplicationVersion ) ) < 21 ; 209 | "Error in parsing XML file (from Xerces)" ; 210 | "Error in parsing XML file (from libxml2)" 211 | ) ; 212 | theCode = 719 ; If ( GetAsNumber ( Get ( ApplicationVersion ) ) < 21 ; 213 | "Error in transforming XML using XSL (from Xalan)" ; 214 | "Error in transforming XML using XSL (from libxslt)" 215 | ) ; 216 | theCode = 720 ; "Error when exporting; intended format does not support repeating fields" ; 217 | theCode = 721 ; "Unknown error occurred in the parser or the transformer" ; 218 | theCode = 722 ; "Cannot import data into a file that has no fields" ; 219 | theCode = 723 ; "You do not have permission to add records to or modify records in the target table" ; 220 | theCode = 724 ; "You do not have permission to add records to the target table" ; 221 | theCode = 725 ; "You do not have permission to modify records in the target table" ; 222 | theCode = 726 ; "Source file has more records than the target table; not all records were imported" ; 223 | theCode = 727 ; "Target table has more records than the source file; not all records were updated" ; 224 | theCode = 729 ; "Errors occurred during import; records could not be imported" ; 225 | theCode = 730 ; "Unsupported Excel version; convert file to the current Excel format and try again" ; 226 | theCode = 731 ; "File you are importing from contains no data" ; 227 | theCode = 732 ; "This file cannot be inserted because it contains other files" ; 228 | theCode = 733 ; "A table cannot be imported into itself" ; 229 | theCode = 734 ; "This file type cannot be displayed as a picture" ; 230 | theCode = 735 ; "This file type cannot be displayed as a picture; it will be inserted and displayed as a file" ; 231 | theCode = 736 ; "Too much data to export to this format; data will be truncated" ; 232 | theCode = 737 ; "Bento table you are importing is missing" ; /* removed in FM14 */ 233 | theCode = 738 ; "The theme you are importing already exists" ; 234 | "Unknown error code" 235 | ) ; 236 | 237 | theCode < 900 ; 238 | Case ( 239 | theCode = 800 ; "Unable to create file on disk" ; 240 | theCode = 801 ; "Unable to create temporary file on System disk" ; 241 | theCode = 802 ; "Unable to open file" ; 242 | theCode = 803 ; "File is single-user, or host cannot be found" ; 243 | theCode = 804 ; "File cannot be opened as read-only in its current state" ; 244 | theCode = 805 ; "File is damaged; use Recover command" ; 245 | theCode = 806 ; "File cannot be opened with this version of a FileMaker client" ; 246 | theCode = 807 ; "File is not a FileMaker Pro file or is severely damaged" ; 247 | theCode = 808 ; "Cannot open file because access privileges are damaged" ; 248 | theCode = 809 ; "Disk/volume is full" ; 249 | theCode = 810 ; "Disk/volume is locked" ; 250 | theCode = 811 ; "Temporary file cannot be opened as FileMaker Pro file" ; 251 | theCode = 812 ; "Exceeded host's capacity" ; /* added in FM13 */ 252 | theCode = 813 ; "Record synchronization error on network" ; 253 | theCode = 814 ; "File(s) cannot be opened because maximum number is open" ; 254 | theCode = 815 ; "Couldn't open lookup file" ; 255 | theCode = 816 ; "Unable to convert file" ; 256 | theCode = 817 ; "Unable to open file because it does not belong to this solution" ; 257 | theCode = 819 ; "Cannot save a local copy of a remote file" ; 258 | theCode = 820 ; "File is being closed" ; 259 | theCode = 821 ; "Host forced a disconnect" ; 260 | theCode = 822 ; "FileMaker Pro files not found; reinstall missing files" ; 261 | theCode = 823 ; "Cannot set file to single-user; guests are connected" ; 262 | theCode = 824 ; "File is damaged or not a FileMaker file" ; 263 | theCode = 825 ; "File is not authorized to reference the protected file" ; 264 | theCode = 826 ; "File path specified is not a valid file path" ; /* added in FM12 */ 265 | theCode = 827 ; "File was not created because the source contained no data or is a reference" ; /* added in FM14 */ 266 | theCode = 850 ; "Path is not valid for the operating system" ; /* added in FM12 */ 267 | theCode = 851 ; "Cannot delete an external file from disk" ; /* added in FM12 */ 268 | theCode = 852 ; "Cannot write a file to the external storage" ; /* added in FM12 */ 269 | theCode = 853 ; "One or more containers failed to transfer" ; /* added in FM13 */ 270 | theCode = 870 ; "Cannot modify file because another user is modifying it" ; /* added in FM18 */ 271 | theCode = 871 ; "Error occurred loading Core ML model" ; /* added in FM19 */ 272 | theCode = 872 ; "Core ML model was not loaded because it contained an unsupported input or output parameter" ; /* added in FM19 */ 273 | theCode = 875 ; "Endpoint is empty" ; /* Added in FM21 */ 274 | theCode = 877 ; "Can't find AI account" ; /* Added in FM21 */ 275 | theCode = 878 ; "JSON data for Options contains a formatting error and couldn't be parsed" ; /* Added in FM21 */ 276 | theCode = 882 ; "Invalid AI request" ; /* Added in FM21 */ 277 | theCode = 883 ; "Invalid request to custom model provider" ; /* Added in FM21 */ 278 | theCode = 884 ; "Invalid AI request" ; /* Added in FM21 */ 279 | theCode = 885 ; "Endpoint is invalid or server is unreachable" ; /* Added in FM21 */ 280 | "Unknown error code" 281 | ) ; 282 | 283 | theCode < 1200 ; 284 | Case ( 285 | theCode = 900 ; "General spelling engine error" ; 286 | theCode = 901 ; "Main spelling dictionary not installed" ; 287 | theCode = 902 ; "Could not launch the Help system" ; /* removed in FM15 */ 288 | theCode = 903 ; "Command cannot be used in a shared file" ; 289 | theCode = 905 ; "Command requires a field to be active" ; 290 | theCode = 906 ; "Current file is not shared; command can be used only if the file is shared" ; 291 | theCode = 920 ; "Cannot initialize the spelling engine" ; 292 | theCode = 921 ; "User dictionary cannot be loaded for editing" ; 293 | theCode = 922 ; "User dictionary cannot be found" ; 294 | theCode = 923 ; "User dictionary is read-only" ; 295 | theCode = 951 ; "An unexpected error occurred" ; /* WPE or REST API */ 296 | theCode = 952 ; "Invalid FileMaker Data API token" ; /* added in FM16, WPE or REST API */ 297 | theCode = 953 ; "Exceeded limit on data the FileMaker Data API and OData can transmit" ; /* added in FM16, WPE or REST API */ 298 | theCode = 954 ; "Unsupported XML grammar" ; /* WPE or REST API */ 299 | theCode = 955 ; "No database name" ; /* WPE or REST API */ 300 | theCode = 956 ; "Maximum number of database or Admin API sessions exceeded" ; /* WPE or REST API */ 301 | theCode = 957 ; "Conflicting commands" ; /* WPE or REST API */ 302 | theCode = 958 ; "Parameter missing" ; /* WPE or REST API */ 303 | theCode = 959 ; "Custom Web Publishing technology is disabled" ; 304 | theCode = 960 ; "Parameter is invalid" ; /* added in FM12 */ 305 | "Unknown error code" 306 | ) ; 307 | 308 | theCode < 1300 ; 309 | Case ( 310 | theCode = 1200 ; "Generic calculation error" ; 311 | theCode = 1201 ; "Too few parameters in the function" ; 312 | theCode = 1202 ; "Too many parameters in the function" ; 313 | theCode = 1203 ; "Unexpected end of calculation" ; 314 | theCode = 1204 ; "Number, text constant, field name, or \"(\" expected" ; 315 | theCode = 1205 ; "Comment is not terminated with \"*/\"" ; 316 | theCode = 1206 ; "Text constant must end with a quotation mark" ; 317 | theCode = 1207 ; "Unbalanced parenthesis" ; 318 | theCode = 1208 ; "Operator missing, function not found, or \"(\" not expected" ; 319 | theCode = 1209 ; "Name (such as field name or layout name) is missing" ; 320 | theCode = 1210 ; "Plug-in function or script step has already been registered" ; 321 | theCode = 1211 ; "List usage is not allowed in this function" ; 322 | theCode = 1212 ; "An operator (for example, +, -, *) is expected here" ; 323 | theCode = 1213 ; "This variable has already been defined in the Let function" ; 324 | theCode = 1214 ; "A function parameter contains an expression where a field is required" ; 325 | theCode = 1215 ; "This parameter is an invalid Get function parameter" ; 326 | theCode = 1216 ; "Only summary fields are allowed as first argument in GetSummary" ; 327 | theCode = 1217 ; "Break field is invalid" ; 328 | theCode = 1218 ; "Cannot evaluate the number" ; 329 | theCode = 1219 ; "A field cannot be used in its own formula" ; 330 | theCode = 1220 ; "Field type must be normal or calculated" ; 331 | theCode = 1221 ; "Data type must be number, date, time, or timestamp" ; 332 | theCode = 1222 ; "Calculation cannot be stored" ; 333 | theCode = 1223 ; "Function referred to is not yet implemented" ; 334 | theCode = 1224 ; "Function referred to does not exist" ; 335 | theCode = 1225 ; "Function referred to is not supported in this context" ; 336 | "Unknown error code" 337 | ) ; 338 | 339 | theCode < 1500 ; 340 | Case ( 341 | theCode = 1300 ; "The specified name can't be used" ; 342 | theCode = 1301 ; "A parameter of the imported or pasted function has the same name as a function in the file" ; /* added in FM13 */ 343 | theCode = 1400 ; "ODBC client driver initialization failed; make sure ODBC client drivers are properly installed" ; 344 | theCode = 1401 ; "Failed to allocate environment (ODBC)" ; 345 | theCode = 1402 ; "Failed to free environment (ODBC)" ; 346 | theCode = 1403 ; "Failed to disconnect (ODBC)" ; 347 | theCode = 1404 ; "Failed to allocate connection (ODBC)" ; 348 | theCode = 1405 ; "Failed to free connection (ODBC)" ; 349 | theCode = 1406 ; "Failed check for SQL API (ODBC)" ; 350 | theCode = 1407 ; "Failed to allocate statement (ODBC)" ; 351 | theCode = 1408 ; "Extended error (ODBC)" ; 352 | theCode = 1409 ; "Error (ODBC)" ; 353 | theCode = 1413 ; "Failed communication link (ODBC)" ; 354 | theCode = 1414 ; "SQL statement is too long" ; /* added in FM12 */ 355 | theCode = 1415 ; "Connection is being disconnected (ODBC)" ; /* added in FM20 */ 356 | theCode = 1450 ; "Action requires PHP privilege extension" ; /* WPE or REST API */ 357 | theCode = 1451 ; "Action requires that current file be remote" ; 358 | "Unknown error code" 359 | ) ; 360 | 361 | theCode < 1600 ; 362 | Case ( 363 | theCode = 1501 ; "SMTP authentication failed" ; 364 | theCode = 1502 ; "Connection refused by SMTP server" ; 365 | theCode = 1503 ; "Error with SSL" ; 366 | theCode = 1504 ; "SMTP server requires the connection to be encrypted" ; 367 | theCode = 1505 ; "Specified authentication is not supported by SMTP server" ; 368 | theCode = 1506 ; "Email message(s) could not be sent successfully" ; 369 | theCode = 1507 ; "Unable to log in to the SMTP server" ; 370 | theCode = 1550 ; "Cannot load the plug-in, or the plug-in is not a valid plug-in" ; /* added in FM12 */ 371 | theCode = 1551 ; "Cannot install the plug-in; cannot delete an existing plug-in or write to the folder or disk" ; /* added in FM12 */ 372 | theCode ≥ 1552 and theCode ≤ 1559 ; "Plug-in Error; see the documentation that came with the plug-in" ; /* added in FM16 */ 373 | "Unknown error code" 374 | ) ; 375 | 376 | theCode < 5500 and theCode ≥ 5000 ; /* added in FM20 */ 377 | /* NOTE: If you use these codes you can add your custom error descriptions here */ 378 | "Revert Transaction" ; 379 | 380 | /* else */ 381 | Case ( 382 | /* 1626-1631 added in FM12 */ 383 | theCode = 1626 ; "Protocol is not supported" ; 384 | theCode = 1627 ; "Authentication failed" ; 385 | theCode = 1628 ; "There was an error with SSL" ; 386 | theCode = 1629 ; "Connection timed out; the timeout value is 60 seconds" ; 387 | theCode = 1630 ; "URL format is incorrect" ; 388 | theCode = 1631 ; "Connection failed" ; 389 | theCode = 1632 ; "The certificate has expired" ; /* added in FM14, major rewording in FM15 */ 390 | theCode = 1633 ; "The certificate is self-signed" ; /* added in FM14, major rewording in FM15 */ 391 | theCode = 1634 ; "A certificate verification error occurred" ; /* added in FM15 */ 392 | theCode = 1635 ; "Connection is unencrypted" ; /* added in FM16 */ 393 | theCode = 1638 ; "The host is not allowing new connections. Try again later." ; /* added in FM21 */ 394 | /* 1700-1711 added in FM18, WPE or REST API */ 395 | theCode = 1700 ; "Resource doesn't exist" ; 396 | theCode = 1701 ; "Host is currently unable to receive requests" ; 397 | theCode = 1702 ; "Authentication information wasn't provided in the correct format; verify the value of the Authorization header" ; 398 | theCode = 1703 ; "Invalid username or password, or JSON Web Token" ; 399 | theCode = 1704 ; "Resource doesn't support the specified HTTP verb" ; 400 | theCode = 1705 ; "Required HTTP header wasn't specified" ; 401 | theCode = 1706 ; "Parameter isn't supported" ; 402 | theCode = 1707 ; "Required parameter wasn't specified in the request" ; 403 | theCode = 1708 ; "Parameter value is invalid" ; 404 | theCode = 1709 ; "Operation is invalid for the resource's current status" ; 405 | theCode = 1710 ; "JSON input isn't syntactically valid" ; 406 | theCode = 1711 ; "Host's license has expired" ; 407 | theCode = 1712 ; "Private key file already exists; remove it and run the command again (*)" ; /* added in FM20 */ 408 | theCode = 1713 ; "The API request is not supported for this operating system (*)" ; /* added in FM20 */ 409 | theCode = 1714 ; "External group name is invalid (*)" ; /* added in FM20 */ 410 | theCode = 1715 ; "External server account sign-in is not enabled (*)" ; /* added in FM20 */ 411 | "Unknown error code" 412 | ) 413 | ) ) 414 | --------------------------------------------------------------------------------