* Assertion failure with git cat-file --batch-command
@ 2026-07-27 9:30 Alan Stokes
2026-07-27 9:57 ` Jeff King
0 siblings, 1 reply; 6+ messages in thread
From: Alan Stokes @ 2026-07-27 9:30 UTC (permalink / raw)
To: git
I unexpectedly managed to hit this:
git: builtin/cat-file.c:387: print_object_or_die: Assertion
`data->info.typep' failed.
Aborted (core dumped)
(That's in print_object_or_die().)
Here's the bugreport.
Thank you for filling out a Git bug report!
Please answer the following questions to help us understand your issue.
What did you do before the bug happened? (Steps to reproduce your issue)
~$ mkdir foo
~$ cd foo
~/foo$ git init
Initialized empty Git repository in /home/alan/foo/.git/
~/foo (main)$ echo hello > hello
~/foo (main)$ git add hello
~/foo (main)$ git commit -m"first"
[main (root-commit) d62fc70] first
1 file changed, 1 insertion(+)
create mode 100644 hello
~/foo (main)$ git ls-tree HEAD
100644 blob ce013625030ba8dba906f756967f9e9ca394464a hello
~/foo (main)$ echo ce013625030ba8dba906f756967f9e9ca394464a | git
cat-file --batch="%(objectsize)"
6
hello
~/foo (main)$ echo info ce013625030ba8dba906f756967f9e9ca394464a | git
cat-file --batch-command="%(objectsize)"
6
~/foo (main)$ echo contents ce013625030ba8dba906f756967f9e9ca394464a |
git cat-file --batch-command="%(objecttype) %(objectsize)"
blob 6
hello
~/foo (main)$ echo contents ce013625030ba8dba906f756967f9e9ca394464a |
git cat-file --batch-command="%(objectsize)"
6
git: builtin/cat-file.c:387: print_object_or_die: Assertion
`data->info.typep' failed.
Aborted (core dumped)
What did you expect to happen? (Expected behavior)
cat-file prints the size of the blob and then the blob contents
What happened instead? (Actual behavior)
Assertion failure, core dump
What's different between what you expected and what actually happened?
The abort
Anything else you want to add:
I first observed this in 2.43.0, but it still seems to be present in
2.54.0.
Note that if I ask git cat-file --batch-command to include the
objecttype in the output it is fine (which gives me a workaround). Or
if I use git cat-file --batch.
IIUC git only fetches the metadata that it needs for each object, and
that is determined from the format. For --batch I guess the type is
always requested, since it is needed to print the object contents. But
for --batch-command that doesn't seem to happen.
I'm not sure what the correct fix is - always request the type in
--batch-command, or perhaps only if a "contents" command is issued?
Please review the rest of the bug report below.
You can delete any lines you don't wish to share.
[System Info]
git version:
git version 2.54.0
cpu: x86_64
no commit associated with this build
sizeof-long: 8
sizeof-size_t: 8
shell-path: /bin/sh
rust: disabled
gettext: enabled
libcurl: 8.5.0
zlib: 1.3
SHA-1: SHA1_DC
SHA-256: SHA256_BLK
default-ref-format: files
default-hash: sha1
uname: Linux 7.0.0-28-generic #28~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC
Wed Jul 1 15:50:57 UTC 2 x86_64
compiler info: gnuc: 13.3
libc info: glibc: 2.39
$SHELL (typically, interactive shell): /bin/bash
[Enabled Hooks]
Best wishes,
Alan
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Assertion failure with git cat-file --batch-command
2026-07-27 9:30 Assertion failure with git cat-file --batch-command Alan Stokes
@ 2026-07-27 9:57 ` Jeff King
2026-07-27 20:26 ` Pablo Sabater
0 siblings, 1 reply; 6+ messages in thread
From: Jeff King @ 2026-07-27 9:57 UTC (permalink / raw)
To: Alan Stokes; +Cc: git
On Mon, Jul 27, 2026 at 10:30:43AM +0100, Alan Stokes wrote:
> I first observed this in 2.43.0, but it still seems to be present in
> 2.54.0.
Yeah, I think this has been there since --batch-command was added.
> Note that if I ask git cat-file --batch-command to include the
> objecttype in the output it is fine (which gives me a workaround). Or
> if I use git cat-file --batch.
>
> IIUC git only fetches the metadata that it needs for each object, and
> that is determined from the format. For --batch I guess the type is
> always requested, since it is needed to print the object contents. But
> for --batch-command that doesn't seem to happen.
Yes, exactly. In the normal --batch code path we have this code:
/*
* If we are printing out the object, then always fill in the type,
* since we will want to decide whether or not to stream.
*/
if (opt->batch_mode == BATCH_MODE_CONTENTS)
data.info.typep = &data.type;
But for command mode, we don't do the same. This makes your case work:
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 1458dd76d6..78eab9723d 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -690,6 +690,7 @@ static void parse_cmd_contents(struct batch_options *opt,
struct expand_data *data)
{
opt->batch_mode = BATCH_MODE_CONTENTS;
+ data->info.typep = &data->type;
batch_one_object(line, output, opt, data);
}
but there's a slight catch. That expand_data is used for every request,
not just the current one. In normal --batch mode, every request wants
the same data (the user-specified format plus the object contents). But
in command mode, some may be "contents" requests and some may just be
"info". The code above turns on type-checking for every request, making
the "info" ones pay to look up the type.
A type lookup isn't all that expensive, but it might matter for some
formats (e.g., just "%(objectname)" does an existence check and nothing
else, so we never even access the object data).
I guess saving and restore data->info.typep would work.
> I'm not sure what the correct fix is - always request the type in
> --batch-command, or perhaps only if a "contents" command is issued?
Yeah, in general if you are asking about "contents" I'd expect you to
get the full name/type/size triple. But it's not wrong to ask for less,
and certainly we should never hit a BUG(). So I think we'd want a fix
along the lines above.
Do you want to try your hand at a patch? It would need to do the
save/restore, and most importantly add a new test to t1006.
-Peff
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: Assertion failure with git cat-file --batch-command
2026-07-27 9:57 ` Jeff King
@ 2026-07-27 20:26 ` Pablo Sabater
2026-07-28 9:08 ` Alan Stokes
0 siblings, 1 reply; 6+ messages in thread
From: Pablo Sabater @ 2026-07-27 20:26 UTC (permalink / raw)
To: Jeff King, Alan Stokes; +Cc: git
On Mon Jul 27, 2026 at 11:57 AM CEST, Jeff King wrote:
> On Mon, Jul 27, 2026 at 10:30:43AM +0100, Alan Stokes wrote:
>
>> I first observed this in 2.43.0, but it still seems to be present in
>> 2.54.0.
>
> Yeah, I think this has been there since --batch-command was added.
>
>> Note that if I ask git cat-file --batch-command to include the
>> objecttype in the output it is fine (which gives me a workaround). Or
>> if I use git cat-file --batch.
>>
>> IIUC git only fetches the metadata that it needs for each object, and
>> that is determined from the format. For --batch I guess the type is
>> always requested, since it is needed to print the object contents. But
>> for --batch-command that doesn't seem to happen.
>
> Yes, exactly. In the normal --batch code path we have this code:
>
> /*
> * If we are printing out the object, then always fill in the type,
> * since we will want to decide whether or not to stream.
> */
> if (opt->batch_mode == BATCH_MODE_CONTENTS)
> data.info.typep = &data.type;
>
> But for command mode, we don't do the same. This makes your case work:
>
> diff --git a/builtin/cat-file.c b/builtin/cat-file.c
> index 1458dd76d6..78eab9723d 100644
> --- a/builtin/cat-file.c
> +++ b/builtin/cat-file.c
> @@ -690,6 +690,7 @@ static void parse_cmd_contents(struct batch_options *opt,
> struct expand_data *data)
> {
> opt->batch_mode = BATCH_MODE_CONTENTS;
> + data->info.typep = &data->type;
> batch_one_object(line, output, opt, data);
> }
>
>
> but there's a slight catch. That expand_data is used for every request,
> not just the current one. In normal --batch mode, every request wants
> the same data (the user-specified format plus the object contents). But
> in command mode, some may be "contents" requests and some may just be
> "info". The code above turns on type-checking for every request, making
> the "info" ones pay to look up the type.
Yes, for example, both 'info' and the 'remote-object-info' series
(marked to 'master' in the last "What's cooking") [1] act on
data->info.typep.
This would make 'info' do a type lookup, and 'remote-object-info'
request "type" even if it wasn't present on the format.
>
> A type lookup isn't all that expensive, but it might matter for some
> formats (e.g., just "%(objectname)" does an existence check and nothing
> else, so we never even access the object data).
Yes, and only the atoms in the format get expanded, a populated type
without its atom in the format won't be shown.
the wasted lookup or a bigger request are the only effect.
>
> I guess saving and restore data->info.typep would work.
Yes I think that too, I tried this and it worked fine:
static void parse_cmd_contents(struct batch_options *opt,
const char *line,
struct strbuf *output,
struct expand_data *data)
{
enum object_type *saved = data->info.typep;
opt->batch_mode = BATCH_MODE_CONTENTS;
data->info.typep = &data->type;
batch_one_object(line, output, opt, data);
data->info.typep = saved;
}
nit: On the current code the parameters aren't indented correctly.
>
>> I'm not sure what the correct fix is - always request the type in
>> --batch-command, or perhaps only if a "contents" command is issued?
>
> Yeah, in general if you are asking about "contents" I'd expect you to
> get the full name/type/size triple. But it's not wrong to ask for less,
> and certainly we should never hit a BUG(). So I think we'd want a fix
> along the lines above.
>
> Do you want to try your hand at a patch? It would need to do the
> save/restore, and most importantly add a new test to t1006.
>
> -Peff
[1]: https://lore.kernel.org/git/20260724-ps-eric-work-rebase-v21-0-ba67f024fdff@gmail.com/
Hope this helps,
Pablo
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Assertion failure with git cat-file --batch-command
2026-07-27 20:26 ` Pablo Sabater
@ 2026-07-28 9:08 ` Alan Stokes
2026-07-28 15:00 ` [PATCH] cat-file: handle content request for --batch-command without type Jeff King
0 siblings, 1 reply; 6+ messages in thread
From: Alan Stokes @ 2026-07-28 9:08 UTC (permalink / raw)
To: Pablo Sabater; +Cc: Jeff King, git
On Mon, 27 Jul 2026 at 21:26, Pablo Sabater <pabloosabaterr@gmail.com> wrote:
>
> On Mon Jul 27, 2026 at 11:57 AM CEST, Jeff King wrote:
> > On Mon, Jul 27, 2026 at 10:30:43AM +0100, Alan Stokes wrote:
> >
> >> I first observed this in 2.43.0, but it still seems to be present in
> >> 2.54.0.
> >
> > Yeah, I think this has been there since --batch-command was added.
> >
> >> Note that if I ask git cat-file --batch-command to include the
> >> objecttype in the output it is fine (which gives me a workaround). Or
> >> if I use git cat-file --batch.
> >>
> >> IIUC git only fetches the metadata that it needs for each object, and
> >> that is determined from the format. For --batch I guess the type is
> >> always requested, since it is needed to print the object contents. But
> >> for --batch-command that doesn't seem to happen.
> >
> > Yes, exactly. In the normal --batch code path we have this code:
> >
> > /*
> > * If we are printing out the object, then always fill in the type,
> > * since we will want to decide whether or not to stream.
> > */
> > if (opt->batch_mode == BATCH_MODE_CONTENTS)
> > data.info.typep = &data.type;
> >
> > But for command mode, we don't do the same. This makes your case work:
> >
> > diff --git a/builtin/cat-file.c b/builtin/cat-file.c
> > index 1458dd76d6..78eab9723d 100644
> > --- a/builtin/cat-file.c
> > +++ b/builtin/cat-file.c
> > @@ -690,6 +690,7 @@ static void parse_cmd_contents(struct batch_options *opt,
> > struct expand_data *data)
> > {
> > opt->batch_mode = BATCH_MODE_CONTENTS;
> > + data->info.typep = &data->type;
> > batch_one_object(line, output, opt, data);
> > }
> >
> >
> > but there's a slight catch. That expand_data is used for every request,
> > not just the current one. In normal --batch mode, every request wants
> > the same data (the user-specified format plus the object contents). But
> > in command mode, some may be "contents" requests and some may just be
> > "info". The code above turns on type-checking for every request, making
> > the "info" ones pay to look up the type.
>
> Yes, for example, both 'info' and the 'remote-object-info' series
> (marked to 'master' in the last "What's cooking") [1] act on
> data->info.typep.
>
> This would make 'info' do a type lookup, and 'remote-object-info'
> request "type" even if it wasn't present on the format.
>
> >
> > A type lookup isn't all that expensive, but it might matter for some
> > formats (e.g., just "%(objectname)" does an existence check and nothing
> > else, so we never even access the object data).
>
> Yes, and only the atoms in the format get expanded, a populated type
> without its atom in the format won't be shown.
> the wasted lookup or a bigger request are the only effect.
>
> >
> > I guess saving and restore data->info.typep would work.
>
> Yes I think that too, I tried this and it worked fine:
>
> static void parse_cmd_contents(struct batch_options *opt,
> const char *line,
> struct strbuf *output,
> struct expand_data *data)
> {
> enum object_type *saved = data->info.typep;
>
> opt->batch_mode = BATCH_MODE_CONTENTS;
> data->info.typep = &data->type;
> batch_one_object(line, output, opt, data);
> data->info.typep = saved;
> }
That does look pretty simple and correct.
>
> nit: On the current code the parameters aren't indented correctly.
>
> >
> >> I'm not sure what the correct fix is - always request the type in
> >> --batch-command, or perhaps only if a "contents" command is issued?
> >
> > Yeah, in general if you are asking about "contents" I'd expect you to
> > get the full name/type/size triple. But it's not wrong to ask for less,
> > and certainly we should never hit a BUG(). So I think we'd want a fix
> > along the lines above.
> >
> > Do you want to try your hand at a patch? It would need to do the
> > save/restore, and most importantly add a new test to t1006.
I would be willing to have a go at it. But realistically I probably won't have
time for a month or two. I'm also a complete noob at the whole posting
patches via email process, so it may be slightly chaotic. If anybody else
wanted to deal with it I obviously wouldn't object.
Best wishes,
Alan
> >
> > -Peff
>
> [1]: https://lore.kernel.org/git/20260724-ps-eric-work-rebase-v21-0-ba67f024fdff@gmail.com/
>
> Hope this helps,
> Pablo
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH] cat-file: handle content request for --batch-command without type
2026-07-28 9:08 ` Alan Stokes
@ 2026-07-28 15:00 ` Jeff King
2026-07-28 17:36 ` Junio C Hamano
0 siblings, 1 reply; 6+ messages in thread
From: Jeff King @ 2026-07-28 15:00 UTC (permalink / raw)
To: Alan Stokes; +Cc: Pablo Sabater, git
On Tue, Jul 28, 2026 at 10:08:46AM +0100, Alan Stokes wrote:
> > > Do you want to try your hand at a patch? It would need to do the
> > > save/restore, and most importantly add a new test to t1006.
>
> I would be willing to have a go at it. But realistically I probably won't have
> time for a month or two. I'm also a complete noob at the whole posting
> patches via email process, so it may be slightly chaotic. If anybody else
> wanted to deal with it I obviously wouldn't object.
That's long enough that I'm worried we'll forget about it. So here's a
patch. Thanks very much for a clear bug report!
-- >8 --
Subject: cat-file: handle content request for --batch-command without type
The batch mode of cat-file needs to know the object's type in order to
print the contents (because it decides whether to stream or not based on
object type). The default batch output contains %(objecttype), so we get
the type info automatically. But when it doesn't, we have to ask for it
explicitly.
In the --batch code path, we check while setting up the object_info
struct whether we will print the contents, and if so set "typep" to get
the value. This comes from 6554dfa97a (cat-file: handle --batch format
with missing type/size, 2013-12-12).
But later we added a --batch-command mode, which does not do the same
trick. The decision about whether to retrieve the contents is made
per-command (a "contents" vs "info" command), so we can't decide when
building the object_info originally. As a result, asking for:
echo "contents HEAD" | git cat-file --batch-command="%(objectname)"
will fail the assertion in print_object_or_die() that the type was
actually filled in.
We can fix it by tweaking the object_info on the fly as we receive each
command. But we should be careful to restore it afterwards; otherwise a
sequence of commands like:
contents $one
info $two
info $three
will pay the type-lookup price for $two and $three when it does not need
to. This wouldn't be incorrect, but just slightly inefficient (and hence
there are no tests for that part, because the externally-visible
behavior is the same).
Reported-by: Alan Stokes <alan@source.dev>
Helped-by: Pablo Sabater <pabloosabaterr@gmail.com>
Signed-off-by: Jeff King <peff@peff.net>
---
builtin/cat-file.c | 3 +++
t/t1006-cat-file.sh | 8 ++++++++
2 files changed, 11 insertions(+)
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 1458dd76d6..ac458c9737 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -689,8 +689,11 @@ static void parse_cmd_contents(struct batch_options *opt,
struct strbuf *output,
struct expand_data *data)
{
+ enum object_type *saved_typep = data->info.typep;
+ data->info.typep = &data->type;
opt->batch_mode = BATCH_MODE_CONTENTS;
batch_one_object(line, output, opt, data);
+ data->info.typep = saved_typep;
}
static void parse_cmd_info(struct batch_options *opt,
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index 762c77c351..f085738082 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -1351,6 +1351,14 @@ test_expect_success 'batch-command flush without --buffer' '
test_grep "^fatal:.*flush is only for --buffer mode.*" err
'
+test_expect_success 'batch-command contents auto-handles type' '
+ echo "HEAD" |
+ git cat-file --batch="%(objectname)" >expect &&
+ echo "contents HEAD" |
+ git cat-file --batch-command="%(objectname)" >actual &&
+ test_cmp expect actual
+'
+
perl_script='
use warnings;
use strict;
--
2.55.0.749.g30c495c7a6
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] cat-file: handle content request for --batch-command without type
2026-07-28 15:00 ` [PATCH] cat-file: handle content request for --batch-command without type Jeff King
@ 2026-07-28 17:36 ` Junio C Hamano
0 siblings, 0 replies; 6+ messages in thread
From: Junio C Hamano @ 2026-07-28 17:36 UTC (permalink / raw)
To: Jeff King; +Cc: Alan Stokes, Pablo Sabater, git
Jeff King <peff@peff.net> writes:
> We can fix it by tweaking the object_info on the fly as we receive each
> command. But we should be careful to restore it afterwards; otherwise a
> sequence of commands like:
>
> contents $one
> info $two
> info $three
>
> will pay the type-lookup price for $two and $three when it does not need
> to. This wouldn't be incorrect, but just slightly inefficient (and hence
> there are no tests for that part, because the externally-visible
> behavior is the same).
Woooo, tricky. I love this kind of attention to details.
The patch text obviously is correct.
Will queue and mark the topic for 'next'. Thanks.
> Reported-by: Alan Stokes <alan@source.dev>
> Helped-by: Pablo Sabater <pabloosabaterr@gmail.com>
> Signed-off-by: Jeff King <peff@peff.net>
> ---
> builtin/cat-file.c | 3 +++
> t/t1006-cat-file.sh | 8 ++++++++
> 2 files changed, 11 insertions(+)
>
> diff --git a/builtin/cat-file.c b/builtin/cat-file.c
> index 1458dd76d6..ac458c9737 100644
> --- a/builtin/cat-file.c
> +++ b/builtin/cat-file.c
> @@ -689,8 +689,11 @@ static void parse_cmd_contents(struct batch_options *opt,
> struct strbuf *output,
> struct expand_data *data)
> {
> + enum object_type *saved_typep = data->info.typep;
> + data->info.typep = &data->type;
> opt->batch_mode = BATCH_MODE_CONTENTS;
> batch_one_object(line, output, opt, data);
> + data->info.typep = saved_typep;
> }
>
> static void parse_cmd_info(struct batch_options *opt,
> diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
> index 762c77c351..f085738082 100755
> --- a/t/t1006-cat-file.sh
> +++ b/t/t1006-cat-file.sh
> @@ -1351,6 +1351,14 @@ test_expect_success 'batch-command flush without --buffer' '
> test_grep "^fatal:.*flush is only for --buffer mode.*" err
> '
>
> +test_expect_success 'batch-command contents auto-handles type' '
> + echo "HEAD" |
> + git cat-file --batch="%(objectname)" >expect &&
> + echo "contents HEAD" |
> + git cat-file --batch-command="%(objectname)" >actual &&
> + test_cmp expect actual
> +'
> +
> perl_script='
> use warnings;
> use strict;
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-07-28 17:36 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-27 9:30 Assertion failure with git cat-file --batch-command Alan Stokes
2026-07-27 9:57 ` Jeff King
2026-07-27 20:26 ` Pablo Sabater
2026-07-28 9:08 ` Alan Stokes
2026-07-28 15:00 ` [PATCH] cat-file: handle content request for --batch-command without type Jeff King
2026-07-28 17:36 ` Junio C Hamano
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox