[GH-ISSUE #7312] [Bug] GGUF accepts 33 nested array frames while advertising a maximum of 32 #4343

Open
opened 2026-10-31 00:49:04 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 26, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/7312

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction

Observed behavior

inspect-model-artifact accepts a GGUF metadata value containing 33 nested arrays when the last array is empty. Adding one UINT8 value to that last array returns exit 1, resource_constraint, and maximum_array_frames: 32. Both 32-array controls succeed; both 34-array controls are refused. The advertised unit is array frames, but the boundary depends on a scalar child that is not an array frame.

Reproduction

From the baseline checkout with its locked dependencies and built CLI, run the following with the pinned Node runtime. It creates tiny aligned GGUF v3 fixtures, isolates the CLI configuration, prints six results, and removes its files. This exact script was executed once after an independent six-case GGUF probe reproduced the same results.

import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join, resolve } from 'node:path';
import { spawnSync } from 'node:child_process';

const cli = resolve('scripts/rea.mjs');
const work = mkdtempSync(join(tmpdir(), 'rea-nesting-'));
const home = join(work, 'home');
mkdirSync(home);
const env = { PATH: process.env.PATH, HOME: home, XDG_CONFIG_HOME: home,
  XDG_CACHE_HOME: home, XDG_DATA_HOME: home, TMPDIR: work };
const u32 = n => { const b = Buffer.alloc(4); b.writeUInt32LE(n); return b; };
const u64 = n => { const b = Buffer.alloc(8); b.writeBigUInt64LE(BigInt(n)); return b; };
const key = Buffer.from('custom.nested');
try {
  for (const arrays of [32, 33, 34]) {
    for (const scalar of [false, true]) {
      let value = Buffer.concat([u32(0), u64(scalar ? 1 : 0),
        scalar ? Buffer.from([7]) : Buffer.alloc(0)]);
      for (let i = 1; i < arrays; i++)
        value = Buffer.concat([u32(9), u64(1), value]);
      const header = Buffer.concat([Buffer.from('GGUF'), u32(3), u64(0),
        u64(1), u64(key.length), key, u32(9), value]);
      const path = join(work, `arrays-${arrays}-${scalar}.gguf`);
      writeFileSync(path, Buffer.concat([header,
        Buffer.alloc((32 - header.length % 32) % 32)]));
      const run = spawnSync(process.execPath, [cli, 'inspect-model-artifact',
        path, '--detail', 'complete', '--json'],
        { env, encoding: 'utf8', timeout: 30000, maxBuffer: 1048576 });
      if (run.error) throw run.error;
      const reply = JSON.parse(run.stdout);
      console.log(JSON.stringify({ arrays, innermost: scalar ? 'scalar' : 'empty',
        exit: run.status, outcome: reply.code ?? 'success',
        limits: reply.details?.reported_limits ?? null }));
    }
  }
} finally {
  rmSync(work, { recursive: true, force: true });
}

Expected behavior

The documented and reported maximum of 32 array frames should describe the actual admission boundary. Under that stated frame-count contract, 33 nested arrays should receive the same typed nesting refusal whether the final array is empty or contains a scalar; 32-array controls should remain accepted. If zero-based value depth is the intended policy, the documentation and reported unit need to describe that convention accurately instead of calling it an array-frame count.

Impact and scope

P3: a bounded discrepancy between the advertised nesting unit and observed admission. The accepted input produced complete metadata with the empty final array; no incorrect tensor declaration, crash, data loss, or consequential resource failure was observed. This report concerns GGUF only. Real-model prevalence and the first affected release are unknown.

REA version

6.8.0; source revision 3233992733c33dabf2de09d22ee4e6d9409f797a.

Runtime and platform

Node.js v24.22.1; macOS 27.0.1 arm64. No external analysis provider or model execution.

Target and artifact context

Synthetic little-endian GGUF v3, zero tensors, one custom.nested ARRAY metadata value. Each enclosing array contains one ARRAY; the final array declares UINT8 elements and count zero or one. Files are 448–480 bytes including explicit 32-byte alignment padding and contain no tensor payload. An independent binary walk confirmed the array counts and exact header extents.

Interface

CLI

Earliest failure stage

Request parsing or validation

Relevant output or evidence

  • Expected source: docs/model-artifacts.md:253-259 limits GGUF metadata nesting to 32 frames; src/model/ModelFormat.ts:75-78,99-100 names 32 array frames in recovery and maximum_array_frames. tests/boundary/model/modelArtifact.test.ts:357-403 checks a 33-array scalar-bearing refusal.
  • Failure source: executed public CLI script above and the independent binary-counted probe; src/model/GgufHeader.ts:109-126,134-164,302 supplies the source-derived counting explanation.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete
Array frames   Innermost   Exit   Result
32             empty       0      success
32             scalar      0      success
33             empty       0      success
33             scalar      1      resource_constraint, maximum_array_frames: 32
34             empty       1      resource_constraint, maximum_array_frames: 32
34             scalar      1      resource_constraint, maximum_array_frames: 32

Every refusal says GGUF metadata nesting exceeds 32 array frames; every invocation had empty stderr. The successful 33-frame input retained one complete metadata row and zero tensors.

Typed outcome or recovery expected

Make the stated counting unit and the six observed outcomes agree. Enforcing the documented 32-array-frame contract requires the empty 33rd array to receive the existing typed nesting refusal while retaining both depth-32 successes and both depth-34 refusals. A documentation/diagnostic correction must instead make the zero-based value-depth convention explicit and accurately explain the empty/scalar boundary.

Analysis or suspected cause

Source-derived: the outer metadata array enters #value at depth 0. Its descendants add one per value invocation, and the guard rejects depths greater than 32. Thus the empty final array is the 33rd logical recursive array invocation at depth 32; its 32 parents are still awaiting it. No scalar child invocation is allocated. A scalar inside that array enters at depth 33 and fails. This explains a value-depth ceiling rather than a count of array frames. Logical parser-frame counts are not measurements of native JavaScript stack usage or harmful resource consumption.

Additional context

Live open/closed issue and all-state PR searches covered GGUF, safetensors, nesting, depth, 33, array frames, and the structured depth limit. No exact model-frame duplicate was found. Closed issue #3960 and PR #3975 repair the separate HAR/qlog parser's 64-container boundary. Closed PR #6088 adds limit-specific model recovery wording and a scalar nesting test, without resolving this empty-array case. These have different closure signals from the GGUF discrepancy reported here.

Triage assessment

  • Impact level: P3
  • Assessment status: supported
  • Impact basis: Tiny public CLI fixtures demonstrate a one-frame discrepancy in the advertised GGUF nesting unit; deeper inputs remain refused, accepted metadata remains complete, and no consequential behavior failure was observed.
  • Workaround status: available
  • Workaround basis: Interpret the existing admission rule as zero-based value depth 32, as established by the source and six CLI controls, rather than relying on the advertised array-frame unit. This requires no artifact modification and preserves the successful inspection result.
Originally created by @coygeek on GitHub (Oct 26, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7312 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Evidence, artifacts, or reconstruction ### Observed behavior `inspect-model-artifact` accepts a GGUF metadata value containing 33 nested arrays when the last array is empty. Adding one UINT8 value to that last array returns exit 1, `resource_constraint`, and `maximum_array_frames: 32`. Both 32-array controls succeed; both 34-array controls are refused. The advertised unit is array frames, but the boundary depends on a scalar child that is not an array frame. ### Reproduction From the baseline checkout with its locked dependencies and built CLI, run the following with the pinned Node runtime. It creates tiny aligned GGUF v3 fixtures, isolates the CLI configuration, prints six results, and removes its files. This exact script was executed once after an independent six-case GGUF probe reproduced the same results. ```js import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join, resolve } from 'node:path'; import { spawnSync } from 'node:child_process'; const cli = resolve('scripts/rea.mjs'); const work = mkdtempSync(join(tmpdir(), 'rea-nesting-')); const home = join(work, 'home'); mkdirSync(home); const env = { PATH: process.env.PATH, HOME: home, XDG_CONFIG_HOME: home, XDG_CACHE_HOME: home, XDG_DATA_HOME: home, TMPDIR: work }; const u32 = n => { const b = Buffer.alloc(4); b.writeUInt32LE(n); return b; }; const u64 = n => { const b = Buffer.alloc(8); b.writeBigUInt64LE(BigInt(n)); return b; }; const key = Buffer.from('custom.nested'); try { for (const arrays of [32, 33, 34]) { for (const scalar of [false, true]) { let value = Buffer.concat([u32(0), u64(scalar ? 1 : 0), scalar ? Buffer.from([7]) : Buffer.alloc(0)]); for (let i = 1; i < arrays; i++) value = Buffer.concat([u32(9), u64(1), value]); const header = Buffer.concat([Buffer.from('GGUF'), u32(3), u64(0), u64(1), u64(key.length), key, u32(9), value]); const path = join(work, `arrays-${arrays}-${scalar}.gguf`); writeFileSync(path, Buffer.concat([header, Buffer.alloc((32 - header.length % 32) % 32)])); const run = spawnSync(process.execPath, [cli, 'inspect-model-artifact', path, '--detail', 'complete', '--json'], { env, encoding: 'utf8', timeout: 30000, maxBuffer: 1048576 }); if (run.error) throw run.error; const reply = JSON.parse(run.stdout); console.log(JSON.stringify({ arrays, innermost: scalar ? 'scalar' : 'empty', exit: run.status, outcome: reply.code ?? 'success', limits: reply.details?.reported_limits ?? null })); } } } finally { rmSync(work, { recursive: true, force: true }); } ``` ### Expected behavior The documented and reported maximum of 32 array frames should describe the actual admission boundary. Under that stated frame-count contract, 33 nested arrays should receive the same typed nesting refusal whether the final array is empty or contains a scalar; 32-array controls should remain accepted. If zero-based value depth is the intended policy, the documentation and reported unit need to describe that convention accurately instead of calling it an array-frame count. ### Impact and scope P3: a bounded discrepancy between the advertised nesting unit and observed admission. The accepted input produced complete metadata with the empty final array; no incorrect tensor declaration, crash, data loss, or consequential resource failure was observed. This report concerns GGUF only. Real-model prevalence and the first affected release are unknown. ### REA version 6.8.0; source revision `3233992733c33dabf2de09d22ee4e6d9409f797a`. ### Runtime and platform Node.js v24.22.1; macOS 27.0.1 arm64. No external analysis provider or model execution. ### Target and artifact context Synthetic little-endian GGUF v3, zero tensors, one `custom.nested` ARRAY metadata value. Each enclosing array contains one ARRAY; the final array declares UINT8 elements and count zero or one. Files are 448–480 bytes including explicit 32-byte alignment padding and contain no tensor payload. An independent binary walk confirmed the array counts and exact header extents. ### Interface CLI ### Earliest failure stage Request parsing or validation ### Relevant output or evidence - Expected source: `docs/model-artifacts.md:253-259` limits GGUF metadata nesting to 32 frames; `src/model/ModelFormat.ts:75-78,99-100` names 32 array frames in recovery and `maximum_array_frames`. `tests/boundary/model/modelArtifact.test.ts:357-403` checks a 33-array scalar-bearing refusal. - Failure source: executed public CLI script above and the independent binary-counted probe; `src/model/GgufHeader.ts:109-126,134-164,302` supplies the source-derived counting explanation. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete ```text Array frames Innermost Exit Result 32 empty 0 success 32 scalar 0 success 33 empty 0 success 33 scalar 1 resource_constraint, maximum_array_frames: 32 34 empty 1 resource_constraint, maximum_array_frames: 32 34 scalar 1 resource_constraint, maximum_array_frames: 32 ``` Every refusal says `GGUF metadata nesting exceeds 32 array frames`; every invocation had empty stderr. The successful 33-frame input retained one complete metadata row and zero tensors. ### Typed outcome or recovery expected Make the stated counting unit and the six observed outcomes agree. Enforcing the documented 32-array-frame contract requires the empty 33rd array to receive the existing typed nesting refusal while retaining both depth-32 successes and both depth-34 refusals. A documentation/diagnostic correction must instead make the zero-based value-depth convention explicit and accurately explain the empty/scalar boundary. ### Analysis or suspected cause Source-derived: the outer metadata array enters `#value` at depth 0. Its descendants add one per value invocation, and the guard rejects depths greater than 32. Thus the empty final array is the 33rd logical recursive array invocation at depth 32; its 32 parents are still awaiting it. No scalar child invocation is allocated. A scalar inside that array enters at depth 33 and fails. This explains a value-depth ceiling rather than a count of array frames. Logical parser-frame counts are not measurements of native JavaScript stack usage or harmful resource consumption. ### Additional context Live open/closed issue and all-state PR searches covered GGUF, safetensors, nesting, depth, 33, array frames, and the structured depth limit. No exact model-frame duplicate was found. Closed [issue #3960](https://github.com/morluto/rea/issues/3960) and [PR #3975](https://github.com/morluto/rea/pull/3975) repair the separate HAR/qlog parser's 64-container boundary. Closed [PR #6088](https://github.com/morluto/rea/pull/6088) adds limit-specific model recovery wording and a scalar nesting test, without resolving this empty-array case. These have different closure signals from the GGUF discrepancy reported here. ## Triage assessment - Impact level: P3 - Assessment status: supported - Impact basis: Tiny public CLI fixtures demonstrate a one-frame discrepancy in the advertised GGUF nesting unit; deeper inputs remain refused, accepted metadata remains complete, and no consequential behavior failure was observed. - Workaround status: available - Workaround basis: Interpret the existing admission rule as zero-based value depth 32, as established by the source and six CLI controls, rather than relying on the advertised array-frame unit. This requires no artifact modification and preserves the successful inspection result.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4343
No description provided.