or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdcommands-and-routing.mdconfiguration-and-context.mddocumentation-and-help.mderror-handling.mdexit-codes.mdflag-parameters.mdindex.mdparameter-parsers.mdpositional-parameters.mdtext-and-localization.md

error-handling.mddocs/

0

# Error Handling

1

2

Comprehensive error types for argument parsing and validation with "did you mean?" suggestions.

3

4

## Quick Reference

5

6

```typescript

7

// Safe error handling in commands (return Error instead of throwing)

8

func: async function(flags) {

9

try {

10

await operation();

11

} catch (err) {

12

return new Error(`Operation failed: ${err.message}`);

13

}

14

}

15

16

// Catch scanner errors

17

try {

18

await run(app, inputs, { process });

19

} catch (err) {

20

if (err instanceof ArgumentScannerError) {

21

// Handle parsing errors

22

console.error(err.message);

23

}

24

}

25

```

26

27

## ArgumentScannerError Hierarchy

28

29

All argument scanning errors extend `ArgumentScannerError`.

30

31

```typescript { .api }

32

abstract class ArgumentScannerError extends Error

33

```

34

35

### Error Types

36

37

| Error | When | Properties |

38

|-------|------|------------|

39

| `FlagNotFoundError` | Unknown flag name | `input`, `corrections`, `aliasName?` |

40

| `AliasNotFoundError` | Unknown alias letter | `input` |

41

| `ArgumentParseError` | Parser threw exception | `externalFlagNameOrPlaceholder`, `input`, `exception` |

42

| `EnumValidationError` | Invalid enum value | `externalFlagName`, `input`, `values`, `corrections` |

43

| `UnsatisfiedFlagError` | Missing required flag value | `externalFlagName`, `nextFlagName?` |

44

| `UnsatisfiedPositionalError` | Missing required argument | `placeholder`, `limit?` |

45

| `UnexpectedPositionalError` | Too many arguments | `expectedCount`, `input` |

46

| `UnexpectedFlagError` | Flag specified multiple times (non-variadic) | `externalFlagName`, `previousInput`, `input` |

47

| `InvalidNegatedFlagSyntaxError` | Value provided for negated flag | `externalFlagName`, `valueText` |

48

49

### Example Scenarios

50

51

```typescript

52

// FlagNotFoundError

53

// myapp --verbos

54

// Error: No flag registered for --verbos, did you mean --verbose?

55

56

// ArgumentParseError

57

// myapp --port abc

58

// Error: Failed to parse "abc" for port: Cannot convert abc to a number

59

60

// EnumValidationError

61

// myapp --env prodution

62

// Error: Expected "prodution" to be one of (dev|staging|prod), did you mean "prod"?

63

64

// UnsatisfiedFlagError

65

// myapp --output

66

// Error: Expected input for flag --output

67

68

// UnsatisfiedPositionalError

69

// myapp (expects 1 arg)

70

// Error: Expected argument for arg1

71

72

// UnexpectedPositionalError

73

// myapp file1 file2 file3 (expects max 2)

74

// Error: Too many arguments, expected 2 but encountered "file3"

75

```

76

77

## Custom Error Formatting

78

79

```typescript

80

import { formatMessageForArgumentScannerError } from "@stricli/core";

81

82

function handleError(error: ArgumentScannerError): string {

83

return formatMessageForArgumentScannerError(error, {

84

FlagNotFoundError: (err) => {

85

if (err.corrections.length > 0) {

86

return `Unknown flag: ${err.input}. Try: ${err.corrections.join(", ")}`;

87

}

88

return `Unknown flag: ${err.input}`;

89

},

90

ArgumentParseError: (err) => {

91

return `Invalid value "${err.input}" for ${err.externalFlagNameOrPlaceholder}`;

92

}

93

});

94

}

95

96

try {

97

await run(app, inputs, { process });

98

} catch (err) {

99

if (err instanceof ArgumentScannerError) {

100

const message = handleError(err);

101

console.error(message);

102

}

103

}

104

```

105

106

## Safe Error Handling in Commands

107

108

Commands can return `Error` instead of throwing for graceful error handling.

109

110

```typescript

111

const command = buildCommand({

112

func: async function(flags, filePath) {

113

try {

114

const content = await readFile(filePath);

115

this.process.stdout.write(content);

116

} catch (err) {

117

// Return Error - Stricli handles it gracefully

118

return new Error(`Failed to read file: ${err.message}`);

119

}

120

},

121

parameters: {

122

positional: {

123

kind: "tuple",

124

parameters: [{ brief: "File path", parse: String }]

125

}

126

},

127

docs: { brief: "Read file" }

128

});

129

```

130

131

## Complete Example

132

133

```typescript

134

import {

135

buildApplication,

136

buildCommand,

137

run,

138

ArgumentScannerError,

139

FlagNotFoundError,

140

ArgumentParseError,

141

formatMessageForArgumentScannerError

142

} from "@stricli/core";

143

144

const app = buildApplication(

145

buildCommand({

146

func: async function(flags) {

147

try {

148

// Operation

149

this.process.stdout.write("Success\n");

150

} catch (err) {

151

return new Error(`Operation failed: ${err.message}`);

152

}

153

},

154

parameters: {

155

flags: {

156

port: {

157

kind: "parsed",

158

parse: (input) => {

159

const port = parseInt(input, 10);

160

if (isNaN(port) || port < 1 || port > 65535) {

161

throw new Error("must be 1-65535");

162

}

163

return port;

164

},

165

brief: "Port"

166

}

167

}

168

},

169

docs: { brief: "Start server" }

170

}),

171

{ name: "server" }

172

);

173

174

try {

175

await run(app, process.argv.slice(2), { process });

176

} catch (err) {

177

if (err instanceof ArgumentScannerError) {

178

const message = formatMessageForArgumentScannerError(err, {

179

FlagNotFoundError: (e) =>

180

`ERROR: Flag "${e.input}" doesn't exist${

181

e.corrections.length > 0 ? `. Did you mean: ${e.corrections.join(", ")}?` : ""

182

}`,

183

ArgumentParseError: (e) =>

184

`ERROR: Invalid value "${e.input}" for --${e.externalFlagNameOrPlaceholder}. ${

185

e.exception instanceof Error ? e.exception.message : ""

186

}`

187

});

188

process.stderr.write(message + "\n");

189

process.exitCode = 1;

190

} else {

191

throw err;

192

}

193

}

194

```

195

196

## Related

197

198

- [Parameter Parsers](./parameter-parsers.md)

199

- [Exit Codes](./exit-codes.md)

200