diem/diem · error

Vector bytecode not supported yet

Error message

Vector bytecode not supported yet

What it means

generate_bytecode ends with an unimplemented!() arm for all vector bytecodes (VecPack, VecLen, VecImmBorrow, VecMutBorrow, VecPushBack, VecPopBack, VecUnpack, VecSwap). Vector operations in the raw bytecode are expected to have been eliminated earlier by function data generation (vector-inlining pass lowering them to calls to intrinsic model functions), so hitting this arm means the input bytecode still contains raw vector instructions.

Source

Thrown at language/move-prover/bytecode/src/stackless_bytecode_generator.rs:1065

                            .get_struct_id(struct_instantiation.def),
                        self.get_type_params(struct_instantiation.type_parameters),
                    ),
                    vec![],
                    vec![value_operand_index, signer_operand_index],
                ));
            }

            MoveBytecode::Nop => self.code.push(Bytecode::Nop(attr_id)),

            // TODO: implement the translation when the the vector-related bytecode is ready
            MoveBytecode::VecPack(..)
            | MoveBytecode::VecLen(_)
            | MoveBytecode::VecImmBorrow(_)
            | MoveBytecode::VecMutBorrow(_)
            | MoveBytecode::VecPushBack(_)
            | MoveBytecode::VecPopBack(_)
            | MoveBytecode::VecUnpack(..)
            | MoveBytecode::VecSwap(_) => unimplemented!("Vector bytecode not supported yet"),
        }
    }

    fn translate_value(ty: &Type, value: &MoveValue) -> Constant {
        match (ty, &value) {
            (Type::Vector(inner), MoveValue::Vector(vs)) => {
                let b = vs
                    .iter()
                    .map(|v| match Self::translate_value(inner, v) {
                        Constant::U8(u) => u,
                        _ => unimplemented!("Not yet supported constant vector type: {:?}", ty),
                    })
                    .collect::<Vec<u8>>();
                Constant::ByteArray(b)
            }
            (Type::Primitive(PrimitiveType::Bool), MoveValue::Bool(b)) => Constant::Bool(*b),
            (Type::Primitive(PrimitiveType::U8), MoveValue::U8(b)) => Constant::U8(*b),
            (Type::Primitive(PrimitiveType::U64), MoveValue::U64(b)) => Constant::U64(*b),

View on GitHub (pinned to fc4714a8ea)

Solutions

  1. Generate function data through the standard move_model pipeline so the vector bytecode is lowered to builtin intrinsic calls before this generator runs
  2. Rewrite the Move code to avoid raw vector ops if driving the generator directly
  3. Upgrade/move to a move-prover version where the vector pass handles your bytecode
  4. If writing a transformation, run/replicate the vector-inlining pass (explore.rs / function data generation) before stackless generation

Example fix

// before: building stackless bytecode directly from compiled module
let gen = StacklessBytecodeGenerator::new(&env);
let func = gen.generate_function(compiled_function);
// after: use FunctionData::gen which applies the vector lowering
env.add_target_function(&function_env, &compiled_function)?;
let func_data = FunctionData::gen(&env, fun_id);
Defensive patterns

Strategy: validation

Validate before calling

// before generation, ensure no raw vector bytecode remains
let has_vec = func.get_code().iter().any(|c| matches!(c,
    MoveBytecode::VecPack(..) | MoveBytecode::VecLen(_) | MoveBytecode::VecImmBorrow(_)
    | MoveBytecode::VecMutBorrow(_) | MoveBytecode::VecPushBack(_)
    | MoveBytecode::VecPopBack(_) | MoveBytecode::VecUnpack(..) | MoveBytecode::VecSwap(_)));
assert!(!has_vec, "vector bytecode must be lowered before stackless generation");

Type guard

fn vector_free(code: &[MoveBytecode]) -> bool {
    !code.iter().any(|c| matches!(c,
        MoveBytecode::VecPack(..) | MoveBytecode::VecLen(_)
        | MoveBytecode::VecImmBorrow(_) | MoveBytecode::VecMutBorrow(_)
        | MoveBytecode::VecPushBack(_) | MoveBytecode::VecPopBack(_)
        | MoveBytecode::VecUnpack(..) | MoveBytecode::VecSwap(_)))
}

Try / catch

match std::panic::catch_unwind(|| generate_bytecode(func)) {
    Ok(bc) => bc,
    Err(_) => return Err("vector bytecode present; run the vector lowering pass first".into()),
}

Prevention

When it happens

Trigger: Running generate_bytecode on a function whose Move bytecode contains vector instructions (VecPushBack, VecPopBack, VecSwap, VecLen, VecBorrow, VecPack/VecUnpack) that were not lowered by the vector pass.

Common situations: Invoking the prover bytecode generator directly on compiled bytecode instead of going through function data generation; using a vector op the prover's inlining pass does not recognize; version mismatch where the vector-elaboration pass is skipped.

Related errors


AI-assisted analysis of diem/diem@fc4714a8ea (2026-09-04). Data as JSON: /api/errors/ae5b1e3598517338. Report an issue: GitHub.