NAME

App::karr::Error - Turn internal errors into one clean user-facing line

VERSION

version 0.600

SYNOPSIS

use App::karr::Error qw( user_error clean_error );

eval { $dir->mkpath; 1 }
  or user_error( "Could not create $dir: ", clean_error($@) );

DESCRIPTION

karr's errors are read by humans and by agents scripting the CLI, so a user-facing message is one line of prose and nothing else. Two things kept breaking that:

  • croak appends " at Some/Module.pm line 42." even when the message already ends in a newline -- the trailing-newline convention that die honours does not apply to Carp. Every croak "...\n" in a command path therefore leaks a module path and a line number at the user.

  • Exceptions raised underneath karr (Path::Tiny, libgit2, a captured git stderr) carry the same call-site suffix plus, often, several more lines of backend chatter.

user_error raises the first kind and clean_error reduces the second kind to something fit to embed in the first. Keep croak for programming errors -- a wrong argument to an internal method -- where the call site is the point.

SEE ALSO

karr, App::karr, App::karr::Git

command_hint

command_hint( 'move', 79, 'in-progress', '--claim', 'NAME' );
# "  karr move 79 in-progress --claim NAME"

Renders one line showing the invocation that would have worked, indented to sit under the message it belongs to and with no trailing newline. The tokens are the words after karr: the real ones the caller typed where they are known, an upper-case placeholder only for the value the caller still has to supply. A token the shell would not take verbatim is single-quoted, so the line can be copied as it stands.

The suggestion is always the last thing a message prints. Agents pipe karr through tail -n, so anything printed in front of a usage block is what gets cut (ticket k263).

set_original_argv

set_original_argv(@ARGV);

Records the caller's own argv, once, before anything rewrites it. bin/karr is the only caller.

original_argv

my $argv = original_argv();   # arrayref, or undef when none was recorded

Reads that argv back as a fresh arrayref. Returns undef where "set_original_argv" was never called, which is how a caller that cannot show the words the user typed knows to print no suggestion at all.

clean_error

my $line = clean_error($@);

Reduces a caught exception to a single line of prose: drops the at FILE line N. call site, keeps only the first line, and trims trailing whitespace. Returns 'unknown error' when nothing is left. Accepts a plain string or an exception object (Git::Libgit2::Error-style objects are read through ->message).

A suggestion block written by "command_hint" is the exception to "one line": those trailing lines are lifted off before the reduction and appended again afterwards, so a message that ends in the command that would have worked keeps it -- and keeps it last.

user_error

user_error("Task $id not found");
user_error( "Could not install skill for $agent: ", clean_error($@) );

Raises a user-facing error whose message reaches STDERR exactly as written, with no module path or line number appended. Parts are concatenated, undef parts are dropped, and trailing whitespace is normalised to the single terminating newline. Never returns.

is_usage_error

exit( is_usage_error($@) ? 2 : 1 );

True when an exception is one of karr's usage errors -- "you called this wrong" rather than "the operation failed" -- decided by the stable leading markers listed in bin/karr. Accepts a plain string or an exception object; a new usage-error die must start with one of those markers, and usage_error in App::karr::Role::ExitCodes is the generic way to emit one.

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/karr/issues.

IRC

Join #langertha on irc.perl.org or message Getty directly.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <getty@cpan.org>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.

This is free software, licensed under:

The Artistic License 2.0 (GPL Compatible)