I'm trying to create an array of structs that contain an array of structs.


From various searching it seems like it is not possible to initialize a struct with an array of structs to be pushed onto a stored array and that the best way seems to simply set a non-struct-array variable at a certain position in the outer array.

Unfortunately, I can't seem to get this to work. I've tried a variety of things, but mostly around the above.

If I run truffle test I get:

Error: VM Exception while processing transaction: revert

If I try running the createBar function in console I get the slightly different:

Error: VM Exception while processing transaction: invalid opcode

I'm not sure what I'm doing wrong. Any light shed or pointers would be greatly appreciated.


An array has a length, you can only use items between 0 y the length of the array - 1.

If you want to add a new element you have to increase the array size.

function createBar(uint barNum)
  returns (uint)
  uint barId = bars.length;
  bars.length += 1;
  bars[barId].barNum = barNum;
  return barId;
  • Wow - this works great. Makes complete sense, I don't know why I didn't think to grow the array like this, I guess I thought I'd read somewhere that arrays magically grow. I'm glad there isn't so much magic in solidity. Thank you! – foobarbaz Jan 3 '18 at 3:14
  • If you want to append only I'd recommend to use the push member, increasing the length manually is not a very good programming technique. – Ismael Jan 3 '18 at 14:13

This is interesting.

I'm not convinced that this sort of nesting is ideal for most cases because unordered lists are not useful for random access. You might find mapped structs with indexes is a little more flexible.

Are there well-solved and simple storage patterns for Solidity?

What you're asking for is workable, so I played around with it. No warranty. ;-)

pragma solidity ^0.4.18;

contract ArrayOfStructsContainsArrayOfStructs {

  struct InnerStruct {
    uint x;

  struct OuterStruct {
    InnerStruct[] innerStructs;

  // This can't be public because the "free" getter is too complex for the compiler to work out a default
  OuterStruct[] outerStructs;

  event LogAppendedOuterStruct(address sender, uint outerStructRow);
  event LogAppendedInnerStruct(address sender, uint outerStructRow, uint innerStructRow);
  event LogSetInnerStructValue(address sender, uint outerStructRow, uint innerStructRow, uint value);

  function appendOuterStruct() public returns(uint row) {
    LogAppendedOuterStruct(msg.sender, outerStructs.length);
    return outerStructs.length-1;

  // The outer structs are in an array, so specify the outerStructRow
  function appendInnerStruct(uint outerStructRow) public returns(uint row) {
    LogAppendedInnerStruct(msg.sender, outerStructRow, outerStructs[outerStructRow].innerStructs.length);
    return outerStructs[outerStructRow].innerStructs.length-1;

  function setInnerStructValue(uint outerStructRow, uint innerStructRow, uint value) public returns(bool success) {
    outerStructs[outerStructRow].innerStructs[innerStructRow].x = value;
    LogSetInnerStructValue(msg.sender, outerStructRow, innerStructRow, value);
    return true;

  function getInnerStructValue(uint outerStructRow, uint innerStructRow) public view returns(uint value) {
    return outerStructs[outerStructRow].innerStructs[innerStructRow].x;


Hope it helps.

  • Thank you for all this! I tried Ismael's below and it does the trick. I worried a little with this solution that the reuse of InnerStruct and OuterStruct would cause things to be duplicated? – foobarbaz Jan 3 '18 at 3:15
  • Ismael had the right idea for appending empty structs to the arrays. I updated the example. It seems better now. – Rob Hitchens Jan 3 '18 at 14:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.